From cbe128926bce3a1ea9d3d0b07fbec6d9082c6761 Mon Sep 17 00:00:00 2001 From: qadeer Date: Thu, 16 Apr 2015 21:29:22 -0700 Subject: patched the type checker to deal with modularity --- Source/Concurrency/TypeCheck.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index f2b2c0ca..845d2140 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -369,6 +369,7 @@ namespace Microsoft.Boogie foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; + if (QKeyValue.FindBoolAttribute(proc.Attributes, "extern")) continue; int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; @@ -560,6 +561,7 @@ namespace Microsoft.Boogie bool isLeftMover = true; bool isRightMover = true; int maxCalleeLayerNum = 0; + int atomicActionCalleeLayerNum = 0; int numAtomicActions = 0; foreach (CallCmd iter in node.CallCmds) { @@ -573,15 +575,23 @@ namespace Microsoft.Boogie if (actionInfo is AtomicActionInfo) { numAtomicActions++; + if (atomicActionCalleeLayerNum == 0) + { + atomicActionCalleeLayerNum = actionInfo.createdAtLayerNum; + } + else if (atomicActionCalleeLayerNum != actionInfo.createdAtLayerNum) + { + Error(node, "All atomic actions must be introduced at the same layer"); + } } } - if (maxCalleeLayerNum < enclosingProcLayerNum && !isLeftMover && !isRightMover && node.CallCmds.Count > 1) + if (numAtomicActions > 1 && !isLeftMover && !isRightMover) { - Error(node, "The callees in the parallel call must be all right movers or all left movers"); + Error(node, "The atomic actions in the parallel call must be all right movers or all left movers"); } - if (maxCalleeLayerNum == enclosingProcLayerNum && numAtomicActions > 0) + if (0 < atomicActionCalleeLayerNum && atomicActionCalleeLayerNum < maxCalleeLayerNum) { - Error(node, "If some callee in the parallel call has the same layer as the enclosing procedure, then no callee can be an atomic action"); + Error(node, "Atomic actions must be introduced at the highest layer"); } return base.VisitParCallCmd(node); } -- cgit v1.2.3 From 6de5d0d2983d33430a1910d6c95cdc217c9de6cb Mon Sep 17 00:00:00 2001 From: qadeer Date: Thu, 16 Apr 2015 22:08:02 -0700 Subject: first check in --- Test/og/par-incr.bpl | 31 +++++++++++++++++++++++++++++++ Test/og/par-incr.bpl.expect | 2 ++ 2 files changed, 33 insertions(+) create mode 100644 Test/og/par-incr.bpl create mode 100644 Test/og/par-incr.bpl.expect diff --git a/Test/og/par-incr.bpl b/Test/og/par-incr.bpl new file mode 100644 index 00000000..7be8f561 --- /dev/null +++ b/Test/og/par-incr.bpl @@ -0,0 +1,31 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +var {:layer 0} x: int; + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:right} |{ A: x := x + 1; return true; }|; + +procedure {:yields} {:layer 1,2} Incr2() +ensures {:right} |{ A: x := x + 2; return true; }|; +{ + yield; + par Incr() | Incr(); + yield; +} + +procedure {:yields} {:layer 1} Yield() +{ + yield; +} + +procedure {:yields} {:layer 2,3} Incr4() +ensures {:atomic} |{ A: x := x + 4; return true; }|; +{ + yield; + par Incr2() | Incr2() | Yield(); + yield; +} + + + diff --git a/Test/og/par-incr.bpl.expect b/Test/og/par-incr.bpl.expect new file mode 100644 index 00000000..00ddb38b --- /dev/null +++ b/Test/og/par-incr.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 4 verified, 0 errors -- cgit v1.2.3 From aad91eb391f331b248969a6e6eac69908a798eca Mon Sep 17 00:00:00 2001 From: qadeer Date: Fri, 17 Apr 2015 15:55:32 -0700 Subject: fixed the treatment of extern --- Source/Concurrency/MoverCheck.cs | 9 ++++----- Source/Concurrency/TypeCheck.cs | 16 +++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Source/Concurrency/MoverCheck.cs b/Source/Concurrency/MoverCheck.cs index 971e7271..ed069d5d 100644 --- a/Source/Concurrency/MoverCheck.cs +++ b/Source/Concurrency/MoverCheck.cs @@ -30,9 +30,9 @@ namespace Microsoft.Boogie if (moverTypeChecker.procToActionInfo.Count == 0) return; - List sortedByCreatedLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo)); + List sortedByCreatedLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; }); - List sortedByAvailableUptoLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo)); + List sortedByAvailableUptoLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; }); Dictionary> pools = new Dictionary>(); @@ -85,10 +85,9 @@ namespace Microsoft.Boogie } } } - foreach (ActionInfo actionInfo in moverTypeChecker.procToActionInfo.Values) + foreach (AtomicActionInfo atomicActionInfo in sortedByCreatedLayerNum) { - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo != null && atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) + if (atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) { moverChecking.CreateNonBlockingChecker(program, atomicActionInfo); } diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index 845d2140..f37a7582 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -23,6 +23,7 @@ namespace Microsoft.Boogie public int createdAtLayerNum; public int availableUptoLayerNum; public bool hasImplementation; + public bool isExtern; public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum) { @@ -30,6 +31,7 @@ namespace Microsoft.Boogie this.createdAtLayerNum = createdAtLayerNum; this.availableUptoLayerNum = availableUptoLayerNum; this.hasImplementation = false; + this.isExtern = QKeyValue.FindBoolAttribute(proc.Attributes, "extern"); } public virtual bool IsRightMover @@ -369,7 +371,6 @@ namespace Microsoft.Boogie foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; - if (QKeyValue.FindBoolAttribute(proc.Attributes, "extern")) continue; int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; @@ -444,16 +445,17 @@ namespace Microsoft.Boogie foreach (var proc in procToActionInfo.Keys) { ActionInfo actionInfo = procToActionInfo[proc]; - if (actionInfo.hasImplementation) continue; - if (leastUnimplementedLayerNum == int.MaxValue) + if (actionInfo.isExtern && actionInfo.hasImplementation) { - leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; + Error(proc, "Extern procedure cannot have an implementation"); + continue; } - else if (leastUnimplementedLayerNum == actionInfo.createdAtLayerNum) + if (actionInfo.isExtern || actionInfo.hasImplementation) continue; + if (leastUnimplementedLayerNum == int.MaxValue) { - // do nothing + leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; } - else + else if (leastUnimplementedLayerNum != actionInfo.createdAtLayerNum) { Error(proc, "All unimplemented atomic actions must be created at the same layer"); } -- cgit v1.2.3 From 7c950ff9a2444a4664243be1eb9fe744d1f4fc87 Mon Sep 17 00:00:00 2001 From: qadeer Date: Sat, 18 Apr 2015 16:04:43 -0700 Subject: changed aux attribute to ghost --- Source/Concurrency/TypeCheck.cs | 30 +++++++++++++++--------------- Test/og/wsq.bpl | 14 +++++++------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index f37a7582..907f7397 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -271,11 +271,11 @@ namespace Microsoft.Boogie public Dictionary procToActionInfo; public Program program; bool canAccessSharedVars; - bool canAccessAuxVars; + bool canAccessGhostVars; int minLayerNum; int maxLayerNum; public Dictionary> absyToLayerNums; - HashSet auxVars; + HashSet ghostVars; public int leastUnimplementedLayerNum; private static List FindLayers(QKeyValue kv) @@ -313,7 +313,7 @@ namespace Microsoft.Boogie public MoverTypeChecker(Program program) { - this.auxVars = new HashSet(); + this.ghostVars = new HashSet(); this.absyToLayerNums = new Dictionary>(); this.globalVarToSharedVarInfo = new Dictionary(); this.procToActionInfo = new Dictionary(); @@ -323,7 +323,7 @@ namespace Microsoft.Boogie this.enclosingProc = null; this.enclosingImpl = null; this.canAccessSharedVars = false; - this.canAccessAuxVars = false; + this.canAccessGhostVars = false; this.minLayerNum = int.MaxValue; this.maxLayerNum = -1; this.leastUnimplementedLayerNum = int.MaxValue; @@ -492,12 +492,12 @@ namespace Microsoft.Boogie } this.enclosingImpl = node; this.enclosingProc = null; - auxVars = new HashSet(); + ghostVars = new HashSet(); foreach (Variable v in node.LocVars) { - if (QKeyValue.FindBoolAttribute(v.Attributes, "aux")) + if (QKeyValue.FindBoolAttribute(v.Attributes, "ghost")) { - auxVars.Add(v); + ghostVars.Add(v); } } return base.VisitImplementation(node); @@ -604,17 +604,17 @@ namespace Microsoft.Boogie for (int i = 0; i < node.Lhss.Count; ++i) { bool savedCanAccessSharedVars = canAccessSharedVars; - bool savedCanAccessAuxVars = canAccessAuxVars; + bool savedCanAccessAuxVars = canAccessGhostVars; Variable v = node.Lhss[i].DeepAssignedVariable; - if (v is LocalVariable && auxVars.Contains(v)) + if (v is LocalVariable && ghostVars.Contains(v)) { canAccessSharedVars = true; - canAccessAuxVars = true; + canAccessGhostVars = true; } this.Visit(node.Lhss[i]); this.Visit(node.Rhss[i]); canAccessSharedVars = savedCanAccessSharedVars; - canAccessAuxVars = savedCanAccessAuxVars; + canAccessGhostVars = savedCanAccessAuxVars; } return node; } @@ -643,9 +643,9 @@ namespace Microsoft.Boogie Error(node, "Accessed shared variable must have layer annotation"); } } - else if (node.Decl is LocalVariable && auxVars.Contains(node.Decl) && !canAccessAuxVars) + else if (node.Decl is LocalVariable && ghostVars.Contains(node.Decl) && !canAccessGhostVars) { - Error(node, "Auxiliary variable can be accessed only in assertions"); + Error(node, "Ghost variable can be accessed only in assertions"); } return base.VisitIdentifierExpr(node); @@ -689,9 +689,9 @@ namespace Microsoft.Boogie minLayerNum = int.MaxValue; maxLayerNum = -1; canAccessSharedVars = true; - canAccessAuxVars = true; + canAccessGhostVars = true; Cmd ret = base.VisitAssertCmd(node); - canAccessAuxVars = false; + canAccessGhostVars = false; canAccessSharedVars = false; CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum); return ret; diff --git a/Test/og/wsq.bpl b/Test/og/wsq.bpl index 9cb6a19b..f4964258 100644 --- a/Test/og/wsq.bpl +++ b/Test/og/wsq.bpl @@ -89,9 +89,9 @@ ensures {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); ensures {:atomic} |{ var i: int; A: assume status[i] == NOT_IN_Q; status[i] := IN_Q; return true; }|; { var t: int; - var {:aux} oldH:int; - var {:aux} oldT:int; - var {:aux} oldStatusT:bool; + var {:ghost} oldH:int; + var {:ghost} oldT:int; + var {:ghost} oldStatusT:bool; oldH := H; @@ -147,8 +147,8 @@ ensures {:atomic} |{ var i: int; A: goto B,C; B: assume status[i] == IN_Q; statu { var h, t: int; var chk: bool; - var {:aux} oldH:int; - var {:aux} oldT:int; + var {:ghost} oldH:int; + var {:ghost} oldT:int; oldH := H; oldT := T; @@ -322,8 +322,8 @@ ensures {:atomic} |{ var i: int; A: goto B,C; B: assume status[i] == IN_Q; statu { var h, t: int; var chk: bool; - var {:aux} oldH:int; - var {:aux} oldT:int; + var {:ghost} oldH:int; + var {:ghost} oldT:int; oldH := H; oldT := T; -- cgit v1.2.3 From 6d56652342dd935f47ce5396d7f7d3a480bbb68e Mon Sep 17 00:00:00 2001 From: qadeer Date: Sat, 18 Apr 2015 17:46:27 -0700 Subject: patched ghost checking --- Source/Concurrency/TypeCheck.cs | 25 +++++++++++++++++++++++-- Test/og/ghost.bpl | 27 +++++++++++++++++++++++++++ Test/og/ghost.bpl.expect | 2 ++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 Test/og/ghost.bpl create mode 100644 Test/og/ghost.bpl.expect diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index 907f7397..c407a7b9 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -474,6 +474,15 @@ namespace Microsoft.Boogie } if (errorCount > 0) return; this.VisitProgram(program); + foreach (Procedure proc in program.Procedures) + { + if (procToActionInfo.ContainsKey(proc)) continue; + foreach (var ie in proc.Modifies) + { + if (!SharedVariables.Contains(ie.Decl)) continue; + Error(proc, "A ghost procedure must not modify a global variable with layer annotation"); + } + } if (errorCount > 0) return; YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); @@ -549,12 +558,24 @@ namespace Microsoft.Boogie { Error(node, "The callee is not available in the caller procedure"); } + return base.VisitCallCmd(node); } else { - Error(node, "Yielding procedure can call only a yielding procedure"); + foreach (var ie in node.Outs) + { + if (ghostVars.Contains(ie.Decl)) continue; + Error(node, "The output of a ghost procedure must be assigned to a ghost variable"); + } + bool savedCanAccessSharedVars = canAccessSharedVars; + bool savedCanAccessAuxVars = canAccessGhostVars; + canAccessSharedVars = true; + canAccessGhostVars = true; + var retVal = base.VisitCallCmd(node); + canAccessSharedVars = savedCanAccessSharedVars; + canAccessGhostVars = savedCanAccessAuxVars; + return retVal; } - return base.VisitCallCmd(node); } public override Cmd VisitParCallCmd(ParCallCmd node) diff --git a/Test/og/ghost.bpl b/Test/og/ghost.bpl new file mode 100644 index 00000000..ef40a232 --- /dev/null +++ b/Test/og/ghost.bpl @@ -0,0 +1,27 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0} x: int; + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:right} |{ A: x := x + 1; return true; }|; + +procedure ghost(y: int) returns (z: int) +requires y == 1; +ensures z == 2; +{ + z := y + 1; +} + +procedure {:yields} {:layer 1,2} Incr2() +ensures {:right} |{ A: x := x + 2; return true; }|; +{ + var {:ghost} a: int; + var {:ghost} b: int; + + yield; + call a := ghost(1); + assert {:layer 1} a == 2; + par Incr() | Incr(); + yield; +} + diff --git a/Test/og/ghost.bpl.expect b/Test/og/ghost.bpl.expect new file mode 100644 index 00000000..41374b00 --- /dev/null +++ b/Test/og/ghost.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 2 verified, 0 errors -- cgit v1.2.3 From 74c6d4d2ce3a2831780be513fe792e436dd8fe12 Mon Sep 17 00:00:00 2001 From: qadeer Date: Sat, 18 Apr 2015 17:50:30 -0700 Subject: added more examples --- Test/og/ghost.bpl | 19 +++++++++++++++++++ Test/og/ghost.bpl.expect | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Test/og/ghost.bpl b/Test/og/ghost.bpl index ef40a232..74d16acf 100644 --- a/Test/og/ghost.bpl +++ b/Test/og/ghost.bpl @@ -25,3 +25,22 @@ ensures {:right} |{ A: x := x + 2; return true; }|; yield; } +procedure ghost_0() returns (z: int) +ensures z == x; +{ + z := x; +} + +procedure {:yields} {:layer 1,2} Incr2_0() +ensures {:right} |{ A: x := x + 2; return true; }|; +{ + var {:ghost} a: int; + var {:ghost} b: int; + + yield; + call a := ghost_0(); + par Incr() | Incr(); + call b := ghost_0(); + assert {:layer 1} b == a + 2; + yield; +} diff --git a/Test/og/ghost.bpl.expect b/Test/og/ghost.bpl.expect index 41374b00..9823d44a 100644 --- a/Test/og/ghost.bpl.expect +++ b/Test/og/ghost.bpl.expect @@ -1,2 +1,2 @@ -Boogie program verifier finished with 2 verified, 0 errors +Boogie program verifier finished with 6 verified, 0 errors -- cgit v1.2.3 From 95a9ed0282811aa2bc3170f41b8b63508918b28e Mon Sep 17 00:00:00 2001 From: akashlal Date: Tue, 21 Apr 2015 12:18:58 +0530 Subject: Better error message --- Source/Houdini/AbstractHoudini.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Source/Houdini/AbstractHoudini.cs b/Source/Houdini/AbstractHoudini.cs index de3d3779..210d9f6c 100644 --- a/Source/Houdini/AbstractHoudini.cs +++ b/Source/Houdini/AbstractHoudini.cs @@ -450,7 +450,18 @@ namespace Microsoft.Boogie.Houdini { } } - var val = prover.Evaluate(arg); + object val; + + try + { + val = prover.Evaluate(arg); + } + catch (ProverInterface.VCExprEvaluationException) + { + Console.WriteLine("AbsHoudni: Error evaluating expression {0}", arg); + throw; + } + if (val is int || val is bool || val is Microsoft.Basetypes.BigNum) { return model.MkElement(val.ToString()); -- cgit v1.2.3 From 4c6dd519143fdbc8ecada56d58103d098c6bd18c Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 22 Apr 2015 09:26:56 -0700 Subject: renamed og to civl --- Test/civl/DeviceCache.bpl | 210 +++++++++++++ Test/civl/DeviceCache.bpl.expect | 2 + Test/civl/FlanaganQadeer.bpl | 75 +++++ Test/civl/FlanaganQadeer.bpl.expect | 2 + Test/civl/Program1.bpl | 33 +++ Test/civl/Program1.bpl.expect | 2 + Test/civl/Program2.bpl | 37 +++ Test/civl/Program2.bpl.expect | 2 + Test/civl/Program3.bpl | 36 +++ Test/civl/Program3.bpl.expect | 2 + Test/civl/Program4.bpl | 68 +++++ Test/civl/Program4.bpl.expect | 2 + Test/civl/Program5.bpl | 79 +++++ Test/civl/Program5.bpl.expect | 2 + Test/civl/akash.bpl | 106 +++++++ Test/civl/akash.bpl.expect | 2 + Test/civl/bar.bpl | 57 ++++ Test/civl/bar.bpl.expect | 13 + Test/civl/chris.bpl | 28 ++ Test/civl/chris.bpl.expect | 2 + Test/civl/chris2.bpl | 34 +++ Test/civl/chris2.bpl.expect | 18 ++ Test/civl/civl-paper.bpl | 175 +++++++++++ Test/civl/civl-paper.bpl.expect | 2 + Test/civl/foo.bpl | 57 ++++ Test/civl/foo.bpl.expect | 8 + Test/civl/ghost.bpl | 46 +++ Test/civl/ghost.bpl.expect | 2 + Test/civl/linear-set.bpl | 105 +++++++ Test/civl/linear-set.bpl.expect | 2 + Test/civl/linear-set2.bpl | 106 +++++++ Test/civl/linear-set2.bpl.expect | 2 + Test/civl/lock-introduced.bpl | 100 +++++++ Test/civl/lock-introduced.bpl.expect | 2 + Test/civl/lock.bpl | 57 ++++ Test/civl/lock.bpl.expect | 2 + Test/civl/lock2.bpl | 63 ++++ Test/civl/lock2.bpl.expect | 2 + Test/civl/multiset.bpl | 324 ++++++++++++++++++++ Test/civl/multiset.bpl.expect | 2 + Test/civl/new1.bpl | 42 +++ Test/civl/new1.bpl.expect | 2 + Test/civl/one.bpl | 18 ++ Test/civl/one.bpl.expect | 2 + Test/civl/par-incr.bpl | 31 ++ Test/civl/par-incr.bpl.expect | 2 + Test/civl/parallel1.bpl | 48 +++ Test/civl/parallel1.bpl.expect | 8 + Test/civl/parallel2.bpl | 59 ++++ Test/civl/parallel2.bpl.expect | 2 + Test/civl/parallel4.bpl | 45 +++ Test/civl/parallel4.bpl.expect | 6 + Test/civl/parallel5.bpl | 59 ++++ Test/civl/parallel5.bpl.expect | 2 + Test/civl/perm.bpl | 49 +++ Test/civl/perm.bpl.expect | 2 + Test/civl/t1.bpl | 103 +++++++ Test/civl/t1.bpl.expect | 9 + Test/civl/termination.bpl | 18 ++ Test/civl/termination.bpl.expect | 3 + Test/civl/termination2.bpl | 19 ++ Test/civl/termination2.bpl.expect | 2 + Test/civl/ticket.bpl | 147 +++++++++ Test/civl/ticket.bpl.expect | 2 + Test/civl/treiber-stack.bpl | 202 +++++++++++++ Test/civl/treiber-stack.bpl.expect | 2 + Test/civl/wsq.bpl | 560 +++++++++++++++++++++++++++++++++++ Test/civl/wsq.bpl.expect | 2 + Test/og/DeviceCache.bpl | 210 ------------- Test/og/DeviceCache.bpl.expect | 2 - Test/og/FlanaganQadeer.bpl | 75 ----- Test/og/FlanaganQadeer.bpl.expect | 2 - Test/og/Program1.bpl | 33 --- Test/og/Program1.bpl.expect | 2 - Test/og/Program2.bpl | 37 --- Test/og/Program2.bpl.expect | 2 - Test/og/Program3.bpl | 36 --- Test/og/Program3.bpl.expect | 2 - Test/og/Program4.bpl | 68 ----- Test/og/Program4.bpl.expect | 2 - Test/og/Program5.bpl | 79 ----- Test/og/Program5.bpl.expect | 2 - Test/og/akash.bpl | 106 ------- Test/og/akash.bpl.expect | 2 - Test/og/bar.bpl | 57 ---- Test/og/bar.bpl.expect | 13 - Test/og/chris.bpl | 28 -- Test/og/chris.bpl.expect | 2 - Test/og/chris2.bpl | 34 --- Test/og/chris2.bpl.expect | 18 -- Test/og/civl-paper.bpl | 175 ----------- Test/og/civl-paper.bpl.expect | 2 - Test/og/foo.bpl | 57 ---- Test/og/foo.bpl.expect | 8 - Test/og/ghost.bpl | 46 --- Test/og/ghost.bpl.expect | 2 - Test/og/linear-set.bpl | 105 ------- Test/og/linear-set.bpl.expect | 2 - Test/og/linear-set2.bpl | 106 ------- Test/og/linear-set2.bpl.expect | 2 - Test/og/lock-introduced.bpl | 100 ------- Test/og/lock-introduced.bpl.expect | 2 - Test/og/lock.bpl | 57 ---- Test/og/lock.bpl.expect | 2 - Test/og/lock2.bpl | 63 ---- Test/og/lock2.bpl.expect | 2 - Test/og/multiset.bpl | 324 -------------------- Test/og/multiset.bpl.expect | 2 - Test/og/new1.bpl | 42 --- Test/og/new1.bpl.expect | 2 - Test/og/one.bpl | 18 -- Test/og/one.bpl.expect | 2 - Test/og/par-incr.bpl | 31 -- Test/og/par-incr.bpl.expect | 2 - Test/og/parallel1.bpl | 48 --- Test/og/parallel1.bpl.expect | 8 - Test/og/parallel2.bpl | 59 ---- Test/og/parallel2.bpl.expect | 2 - Test/og/parallel4.bpl | 45 --- Test/og/parallel4.bpl.expect | 6 - Test/og/parallel5.bpl | 59 ---- Test/og/parallel5.bpl.expect | 2 - Test/og/perm.bpl | 49 --- Test/og/perm.bpl.expect | 2 - Test/og/t1.bpl | 103 ------- Test/og/t1.bpl.expect | 9 - Test/og/termination.bpl | 18 -- Test/og/termination.bpl.expect | 3 - Test/og/termination2.bpl | 19 -- Test/og/termination2.bpl.expect | 2 - Test/og/ticket.bpl | 147 --------- Test/og/ticket.bpl.expect | 2 - Test/og/treiber-stack.bpl | 202 ------------- Test/og/treiber-stack.bpl.expect | 2 - Test/og/wsq.bpl | 560 ----------------------------------- Test/og/wsq.bpl.expect | 2 - 136 files changed, 3315 insertions(+), 3315 deletions(-) create mode 100644 Test/civl/DeviceCache.bpl create mode 100644 Test/civl/DeviceCache.bpl.expect create mode 100644 Test/civl/FlanaganQadeer.bpl create mode 100644 Test/civl/FlanaganQadeer.bpl.expect create mode 100644 Test/civl/Program1.bpl create mode 100644 Test/civl/Program1.bpl.expect create mode 100644 Test/civl/Program2.bpl create mode 100644 Test/civl/Program2.bpl.expect create mode 100644 Test/civl/Program3.bpl create mode 100644 Test/civl/Program3.bpl.expect create mode 100644 Test/civl/Program4.bpl create mode 100644 Test/civl/Program4.bpl.expect create mode 100644 Test/civl/Program5.bpl create mode 100644 Test/civl/Program5.bpl.expect create mode 100644 Test/civl/akash.bpl create mode 100644 Test/civl/akash.bpl.expect create mode 100644 Test/civl/bar.bpl create mode 100644 Test/civl/bar.bpl.expect create mode 100644 Test/civl/chris.bpl create mode 100644 Test/civl/chris.bpl.expect create mode 100644 Test/civl/chris2.bpl create mode 100644 Test/civl/chris2.bpl.expect create mode 100644 Test/civl/civl-paper.bpl create mode 100644 Test/civl/civl-paper.bpl.expect create mode 100644 Test/civl/foo.bpl create mode 100644 Test/civl/foo.bpl.expect create mode 100644 Test/civl/ghost.bpl create mode 100644 Test/civl/ghost.bpl.expect create mode 100644 Test/civl/linear-set.bpl create mode 100644 Test/civl/linear-set.bpl.expect create mode 100644 Test/civl/linear-set2.bpl create mode 100644 Test/civl/linear-set2.bpl.expect create mode 100644 Test/civl/lock-introduced.bpl create mode 100644 Test/civl/lock-introduced.bpl.expect create mode 100644 Test/civl/lock.bpl create mode 100644 Test/civl/lock.bpl.expect create mode 100644 Test/civl/lock2.bpl create mode 100644 Test/civl/lock2.bpl.expect create mode 100644 Test/civl/multiset.bpl create mode 100644 Test/civl/multiset.bpl.expect create mode 100644 Test/civl/new1.bpl create mode 100644 Test/civl/new1.bpl.expect create mode 100644 Test/civl/one.bpl create mode 100644 Test/civl/one.bpl.expect create mode 100644 Test/civl/par-incr.bpl create mode 100644 Test/civl/par-incr.bpl.expect create mode 100644 Test/civl/parallel1.bpl create mode 100644 Test/civl/parallel1.bpl.expect create mode 100644 Test/civl/parallel2.bpl create mode 100644 Test/civl/parallel2.bpl.expect create mode 100644 Test/civl/parallel4.bpl create mode 100644 Test/civl/parallel4.bpl.expect create mode 100644 Test/civl/parallel5.bpl create mode 100644 Test/civl/parallel5.bpl.expect create mode 100644 Test/civl/perm.bpl create mode 100644 Test/civl/perm.bpl.expect create mode 100644 Test/civl/t1.bpl create mode 100644 Test/civl/t1.bpl.expect create mode 100644 Test/civl/termination.bpl create mode 100644 Test/civl/termination.bpl.expect create mode 100644 Test/civl/termination2.bpl create mode 100644 Test/civl/termination2.bpl.expect create mode 100644 Test/civl/ticket.bpl create mode 100644 Test/civl/ticket.bpl.expect create mode 100644 Test/civl/treiber-stack.bpl create mode 100644 Test/civl/treiber-stack.bpl.expect create mode 100644 Test/civl/wsq.bpl create mode 100644 Test/civl/wsq.bpl.expect delete mode 100644 Test/og/DeviceCache.bpl delete mode 100644 Test/og/DeviceCache.bpl.expect delete mode 100644 Test/og/FlanaganQadeer.bpl delete mode 100644 Test/og/FlanaganQadeer.bpl.expect delete mode 100644 Test/og/Program1.bpl delete mode 100644 Test/og/Program1.bpl.expect delete mode 100644 Test/og/Program2.bpl delete mode 100644 Test/og/Program2.bpl.expect delete mode 100644 Test/og/Program3.bpl delete mode 100644 Test/og/Program3.bpl.expect delete mode 100644 Test/og/Program4.bpl delete mode 100644 Test/og/Program4.bpl.expect delete mode 100644 Test/og/Program5.bpl delete mode 100644 Test/og/Program5.bpl.expect delete mode 100644 Test/og/akash.bpl delete mode 100644 Test/og/akash.bpl.expect delete mode 100644 Test/og/bar.bpl delete mode 100644 Test/og/bar.bpl.expect delete mode 100644 Test/og/chris.bpl delete mode 100644 Test/og/chris.bpl.expect delete mode 100644 Test/og/chris2.bpl delete mode 100644 Test/og/chris2.bpl.expect delete mode 100644 Test/og/civl-paper.bpl delete mode 100644 Test/og/civl-paper.bpl.expect delete mode 100644 Test/og/foo.bpl delete mode 100644 Test/og/foo.bpl.expect delete mode 100644 Test/og/ghost.bpl delete mode 100644 Test/og/ghost.bpl.expect delete mode 100644 Test/og/linear-set.bpl delete mode 100644 Test/og/linear-set.bpl.expect delete mode 100644 Test/og/linear-set2.bpl delete mode 100644 Test/og/linear-set2.bpl.expect delete mode 100644 Test/og/lock-introduced.bpl delete mode 100644 Test/og/lock-introduced.bpl.expect delete mode 100644 Test/og/lock.bpl delete mode 100644 Test/og/lock.bpl.expect delete mode 100644 Test/og/lock2.bpl delete mode 100644 Test/og/lock2.bpl.expect delete mode 100644 Test/og/multiset.bpl delete mode 100644 Test/og/multiset.bpl.expect delete mode 100644 Test/og/new1.bpl delete mode 100644 Test/og/new1.bpl.expect delete mode 100644 Test/og/one.bpl delete mode 100644 Test/og/one.bpl.expect delete mode 100644 Test/og/par-incr.bpl delete mode 100644 Test/og/par-incr.bpl.expect delete mode 100644 Test/og/parallel1.bpl delete mode 100644 Test/og/parallel1.bpl.expect delete mode 100644 Test/og/parallel2.bpl delete mode 100644 Test/og/parallel2.bpl.expect delete mode 100644 Test/og/parallel4.bpl delete mode 100644 Test/og/parallel4.bpl.expect delete mode 100644 Test/og/parallel5.bpl delete mode 100644 Test/og/parallel5.bpl.expect delete mode 100644 Test/og/perm.bpl delete mode 100644 Test/og/perm.bpl.expect delete mode 100644 Test/og/t1.bpl delete mode 100644 Test/og/t1.bpl.expect delete mode 100644 Test/og/termination.bpl delete mode 100644 Test/og/termination.bpl.expect delete mode 100644 Test/og/termination2.bpl delete mode 100644 Test/og/termination2.bpl.expect delete mode 100644 Test/og/ticket.bpl delete mode 100644 Test/og/ticket.bpl.expect delete mode 100644 Test/og/treiber-stack.bpl delete mode 100644 Test/og/treiber-stack.bpl.expect delete mode 100644 Test/og/wsq.bpl delete mode 100644 Test/og/wsq.bpl.expect diff --git a/Test/civl/DeviceCache.bpl b/Test/civl/DeviceCache.bpl new file mode 100644 index 00000000..f439b607 --- /dev/null +++ b/Test/civl/DeviceCache.bpl @@ -0,0 +1,210 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type X; +function {:builtin "MapConst"} mapconstbool(bool): [X]bool; +const nil: X; +var {:layer 0,1} ghostLock: X; +var {:layer 0,1} lock: X; +var {:layer 0,1} currsize: int; +var {:layer 0,1} newsize: int; + +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool +{ + MapConstBool(false)[x := true] +} +function {:inline} {:linear "tid"} TidSetCollector(x: [X]bool) : [X]bool +{ + x +} + +function {:inline} Inv(ghostLock: X, currsize: int, newsize: int) : (bool) +{ + 0 <= currsize && currsize <= newsize && + (ghostLock == nil <==> currsize == newsize) +} + +procedure {:yields} {:layer 1} Yield() +requires {:layer 1} Inv(ghostLock, currsize, newsize); +ensures {:layer 1} Inv(ghostLock, currsize, newsize); +{ + yield; + assert {:layer 1} Inv(ghostLock, currsize, newsize); +} + +procedure {:yields} {:layer 1} YieldToReadCache({:linear "tid"} tid: X) +requires {:layer 1} Inv(ghostLock, currsize, newsize) && tid != nil; +ensures {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) <= currsize; +{ + yield; + assert {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) <= currsize; +} + +procedure {:yields} {:layer 1} YieldToWriteCache({:linear "tid"} tid: X) +requires {:layer 1} Inv(ghostLock, currsize, newsize) && ghostLock == tid && tid != nil; +ensures {:layer 1} Inv(ghostLock, currsize, newsize) && ghostLock == tid && old(currsize) == currsize && old(newsize) == newsize; +{ + yield; + assert {:layer 1} Inv(ghostLock, currsize, newsize) && tid != nil && ghostLock == tid && old(currsize) == currsize && old(newsize) == newsize; +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: X) +ensures {:layer 1} xl != nil; +{ + yield; + call xl := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 1} main({:linear_in "tid"} xls: [X]bool) +requires {:layer 1} xls == mapconstbool(true); +{ + var {:linear "tid"} tid: X; + + yield; + + call Init(xls); + + yield; + assert {:layer 1} Inv(ghostLock, currsize, newsize); + + while (*) + invariant {:layer 1} Inv(ghostLock, currsize, newsize); + { + par tid := Allocate() | Yield(); + yield; + assert {:layer 1} Inv(ghostLock, currsize, newsize); + async call Thread(tid); + yield; + assert {:layer 1} Inv(ghostLock, currsize, newsize); + } + yield; +} + +procedure {:yields} {:layer 1} Thread({:linear "tid"} tid: X) +requires {:layer 1} tid != nil; +requires {:layer 1} Inv(ghostLock, currsize, newsize); +{ + var start, size, bytesRead: int; + + havoc start, size; + assume (0 <= start && 0 <= size); + call bytesRead := Read(tid, start, size); +} + +procedure {:yields} {:layer 1} Read({:linear "tid"} tid: X, start : int, size : int) returns (bytesRead : int) +requires {:layer 1} tid != nil; +requires {:layer 1} 0 <= start && 0 <= size; +requires {:layer 1} Inv(ghostLock, currsize, newsize); +ensures {:layer 1} 0 <= bytesRead && bytesRead <= size; +{ + var i, tmp: int; + + par YieldToReadCache(tid); + bytesRead := size; + call acquire(tid); + call i := ReadCurrsize(tid); + call tmp := ReadNewsize(tid); + if (start + size <= i) { + call release(tid); + goto COPY_TO_BUFFER; + } else if (tmp > i) { + bytesRead := if (start <= i) then (i - start) else 0; + call release(tid); + goto COPY_TO_BUFFER; + } else { + call WriteNewsize(tid, start + size); + call release(tid); + goto READ_DEVICE; + } + +READ_DEVICE: + par YieldToWriteCache(tid); + call WriteCache(tid, start + size); + par YieldToWriteCache(tid); + call acquire(tid); + call tmp := ReadNewsize(tid); + call WriteCurrsize(tid, tmp); + call release(tid); + +COPY_TO_BUFFER: + par YieldToReadCache(tid); + call ReadCache(tid, start, bytesRead); +} + +procedure {:yields} {:layer 1} WriteCache({:linear "tid"} tid: X, index: int) +requires {:layer 1} Inv(ghostLock, currsize, newsize); +requires {:layer 1} ghostLock == tid && tid != nil; +ensures {:layer 1} ghostLock == tid; +ensures {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) == currsize && old(newsize) == newsize; +{ + var j: int; + + par YieldToWriteCache(tid); + call j := ReadCurrsize(tid); + while (j < index) + invariant {:layer 1} ghostLock == tid && currsize <= j && tid == tid; + invariant {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) == currsize && old(newsize) == newsize; + { + par YieldToWriteCache(tid); + call WriteCacheEntry(tid, j); + j := j + 1; + } + par YieldToWriteCache(tid); +} + +procedure {:yields} {:layer 1} ReadCache({:linear "tid"} tid: X, start: int, bytesRead: int) +requires {:layer 1} Inv(ghostLock, currsize, newsize); +requires {:layer 1} tid != nil; +requires {:layer 1} 0 <= start && 0 <= bytesRead; +requires {:layer 1} (bytesRead == 0 || start + bytesRead <= currsize); +ensures {:layer 1} Inv(ghostLock, currsize, newsize); +{ + var j: int; + + par YieldToReadCache(tid); + + j := 0; + while(j < bytesRead) + invariant {:layer 1} 0 <= j; + invariant {:layer 1} bytesRead == 0 || start + bytesRead <= currsize; + invariant {:layer 1} Inv(ghostLock, currsize, newsize); + { + assert {:layer 1} start + j < currsize; + call ReadCacheEntry(tid, start + j); + j := j + 1; + par YieldToReadCache(tid); + } + + par YieldToReadCache(tid); +} + +procedure {:yields} {:layer 0,1} Init({:linear_in "tid"} xls:[X]bool); +ensures {:atomic} |{ A: assert xls == mapconstbool(true); currsize := 0; newsize := 0; lock := nil; ghostLock := nil; return true; }|; + +procedure {:yields} {:layer 0,1} ReadCurrsize({:linear "tid"} tid: X) returns (val: int); +ensures {:right} |{A: assert tid != nil; assert lock == tid || ghostLock == tid; val := currsize; return true; }|; + +procedure {:yields} {:layer 0,1} ReadNewsize({:linear "tid"} tid: X) returns (val: int); +ensures {:right} |{A: assert tid != nil; assert lock == tid || ghostLock == tid; val := newsize; return true; }|; + +procedure {:yields} {:layer 0,1} WriteNewsize({:linear "tid"} tid: X, val: int); +ensures {:atomic} |{A: assert tid != nil; assert lock == tid && ghostLock == nil; newsize := val; ghostLock := tid; return true; }|; + +procedure {:yields} {:layer 0,1} WriteCurrsize({:linear "tid"} tid: X, val: int); +ensures {:atomic} |{A: assert tid != nil; assert lock == tid && ghostLock == tid; currsize := val; ghostLock := nil; return true; }|; + +procedure {:yields} {:layer 0,1} ReadCacheEntry({:linear "tid"} tid: X, index: int); +ensures {:atomic} |{ A: assert 0 <= index && index < currsize; return true; }|; + +procedure {:yields} {:layer 0,1} WriteCacheEntry({:linear "tid"} tid: X, index: int); +ensures {:right} |{ A: assert tid != nil; assert currsize <= index && ghostLock == tid; return true; }|; + +procedure {:yields} {:layer 0,1} acquire({:linear "tid"} tid: X); +ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; + +procedure {:yields} {:layer 0,1} release({:linear "tid"} tid: X); +ensures {:left} |{ A: assert tid != nil; assert lock == tid; lock := nil; return true; }|; + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: X); +ensures {:atomic} |{ A: assume tid != nil; return true; }|; diff --git a/Test/civl/DeviceCache.bpl.expect b/Test/civl/DeviceCache.bpl.expect new file mode 100644 index 00000000..9ec7a92d --- /dev/null +++ b/Test/civl/DeviceCache.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 30 verified, 0 errors diff --git a/Test/civl/FlanaganQadeer.bpl b/Test/civl/FlanaganQadeer.bpl new file mode 100644 index 00000000..7345b5b2 --- /dev/null +++ b/Test/civl/FlanaganQadeer.bpl @@ -0,0 +1,75 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type X; +const nil: X; +var {:layer 0,1} l: X; +var {:layer 0,1} x: int; + +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool +{ + MapConstBool(false)[x := true] +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: X) +ensures {:layer 1} xl != nil; +{ + yield; + call xl := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 1} main() +{ + var {:linear "tid"} tid: X; + var val: int; + + yield; + while (*) + { + call tid := Allocate(); + havoc val; + async call foo(tid, val); + yield; + } + yield; +} +procedure {:yields} {:layer 0,1} Lock(tid: X); +ensures {:atomic} |{A: assume l == nil; l := tid; return true; }|; + +procedure {:yields} {:layer 0,1} Unlock(); +ensures {:atomic} |{A: l := nil; return true; }|; + +procedure {:yields} {:layer 0,1} Set(val: int); +ensures {:atomic} |{A: x := val; return true; }|; + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xl: X); +ensures {:atomic} |{ A: assume xl != nil; return true; }|; + +procedure {:yields} {:layer 1} foo({:linear_in "tid"} tid': X, val: int) +requires {:layer 1} tid' != nil; +{ + var {:linear "tid"} tid: X; + tid := tid'; + + yield; + call Lock(tid); + call tid := Yield(tid); + call Set(val); + call tid := Yield(tid); + assert {:layer 1} x == val; + call tid := Yield(tid); + call Unlock(); + yield; +} + +procedure {:yields} {:layer 1} Yield({:linear_in "tid"} tid': X) returns ({:linear "tid"} tid: X) +requires {:layer 1} tid' != nil; +ensures {:layer 1} tid == tid'; +ensures {:layer 1} old(l) == tid ==> old(l) == l && old(x) == x; +{ + tid := tid'; + yield; + assert {:layer 1} tid != nil; + assert {:layer 1} (old(l) == tid ==> old(l) == l && old(x) == x); +} \ No newline at end of file diff --git a/Test/civl/FlanaganQadeer.bpl.expect b/Test/civl/FlanaganQadeer.bpl.expect new file mode 100644 index 00000000..fef5ddc0 --- /dev/null +++ b/Test/civl/FlanaganQadeer.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/civl/Program1.bpl b/Test/civl/Program1.bpl new file mode 100644 index 00000000..f405b92a --- /dev/null +++ b/Test/civl/Program1.bpl @@ -0,0 +1,33 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} x:int; + +procedure {:yields} {:layer 1} p() +requires {:layer 1} x >= 5; +ensures {:layer 1} x >= 8; +{ + yield; + assert {:layer 1} x >= 5; + call Incr(1); + yield; + assert {:layer 1} x >= 6; + call Incr(1); + yield; + assert {:layer 1} x >= 7; + call Incr(1); + yield; + assert {:layer 1} x >= 8; +} + +procedure {:yields} {:layer 1} q() +{ + yield; + call Incr(3); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(val: int); +ensures {:atomic} +|{A: + x := x + val; return true; +}|; diff --git a/Test/civl/Program1.bpl.expect b/Test/civl/Program1.bpl.expect new file mode 100644 index 00000000..3de74d3e --- /dev/null +++ b/Test/civl/Program1.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 2 verified, 0 errors diff --git a/Test/civl/Program2.bpl b/Test/civl/Program2.bpl new file mode 100644 index 00000000..75c83c67 --- /dev/null +++ b/Test/civl/Program2.bpl @@ -0,0 +1,37 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} x:int; + +procedure {:yields} {:layer 1} yield_x(n: int) +requires {:layer 1} x >= n; +ensures {:layer 1} x >= n; +{ + yield; + assert {:layer 1} x >= n; +} + +procedure {:yields} {:layer 1} p() +requires {:layer 1} x >= 5; +ensures {:layer 1} x >= 8; +{ + call yield_x(5); + call Incr(1); + call yield_x(6); + call Incr(1); + call yield_x(7); + call Incr(1); + call yield_x(8); +} + +procedure {:yields} {:layer 1} q() +{ + yield; + call Incr(3); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(val: int); +ensures {:atomic} +|{A: + x := x + val; return true; +}|; diff --git a/Test/civl/Program2.bpl.expect b/Test/civl/Program2.bpl.expect new file mode 100644 index 00000000..5b2909f1 --- /dev/null +++ b/Test/civl/Program2.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/civl/Program3.bpl b/Test/civl/Program3.bpl new file mode 100644 index 00000000..f8c4e132 --- /dev/null +++ b/Test/civl/Program3.bpl @@ -0,0 +1,36 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} x:int; + +procedure {:yields} {:layer 1} yield_x() +ensures {:layer 1} x >= old(x); +{ + yield; + assert {:layer 1} x >= old(x); +} + +procedure {:yields} {:layer 1} p() +requires {:layer 1} x >= 5; +ensures {:layer 1} x >= 8; +{ + call yield_x(); + call Incr(1); + call yield_x(); + call Incr(1); + call yield_x(); + call Incr(1); + call yield_x(); +} + +procedure {:yields} {:layer 1} q() +{ + yield; + call Incr(3); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(val: int); +ensures {:atomic} +|{A: + x := x + val; return true; +}|; diff --git a/Test/civl/Program3.bpl.expect b/Test/civl/Program3.bpl.expect new file mode 100644 index 00000000..5b2909f1 --- /dev/null +++ b/Test/civl/Program3.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/civl/Program4.bpl b/Test/civl/Program4.bpl new file mode 100644 index 00000000..7f2f9c44 --- /dev/null +++ b/Test/civl/Program4.bpl @@ -0,0 +1,68 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type Tid; +var {:layer 0,1} a:[Tid]int; + +procedure {:yields} {:layer 1} main() { + var {:linear "tid"} tid:Tid; + + yield; + while (true) { + call tid := Allocate(); + async call P(tid); + yield; + } + yield; +} + +procedure {:yields} {:layer 1} P({:linear "tid"} tid: Tid) +ensures {:layer 1} a[tid] == old(a)[tid] + 1; +{ + var t:int; + + yield; + assert {:layer 1} a[tid] == old(a)[tid]; + call t := Read(tid); + yield; + assert {:layer 1} a[tid] == t; + call Write(tid, t + 1); + yield; + assert {:layer 1} a[tid] == t + 1; +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: Tid) +{ + yield; + call tid := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 0,1} Read({:linear "tid"} tid: Tid) returns (val: int); +ensures {:atomic} +|{A: + val := a[tid]; return true; +}|; + +procedure {:yields} {:layer 0,1} Write({:linear "tid"} tid: Tid, val: int); +ensures {:atomic} +|{A: + a[tid] := val; return true; +}|; + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: Tid); +ensures {:atomic} |{ A: return true; }|; + + + +function {:builtin "MapConst"} MapConstBool(bool): [Tid]bool; +function {:builtin "MapOr"} MapOr([Tid]bool, [Tid]bool) : [Tid]bool; + +function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool +{ + MapConstBool(false)[x := true] +} +function {:inline} {:linear "tid"} TidSetCollector(x: [Tid]bool) : [Tid]bool +{ + x +} + diff --git a/Test/civl/Program4.bpl.expect b/Test/civl/Program4.bpl.expect new file mode 100644 index 00000000..5b2909f1 --- /dev/null +++ b/Test/civl/Program4.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/civl/Program5.bpl b/Test/civl/Program5.bpl new file mode 100644 index 00000000..7ede3124 --- /dev/null +++ b/Test/civl/Program5.bpl @@ -0,0 +1,79 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type Tid; +const unique nil: Tid; + +function {:inline} UNALLOC():int { 0 } +function {:inline} WHITE():int { 1 } +function {:inline} GRAY():int { 2 } +function {:inline} BLACK():int { 3 } +function {:inline} Unalloc(i:int) returns(bool) { i <= 0 } +function {:inline} White(i:int) returns(bool) { i == 1 } +function {:inline} Gray(i:int) returns(bool) { i == 2 } +function {:inline} Black(i:int) returns(bool) { i >= 3 } + +procedure {:yields} {:layer 2} YieldColorOnlyGetsDarker() +ensures {:layer 2} Color >= old(Color); +{ + yield; + assert {:layer 2} Color >= old(Color); +} + +procedure {:yields} {:layer 2,3} WriteBarrier({:linear "tid"} tid:Tid) +ensures {:atomic} |{ A: assert tid != nil; goto B, C; + B: assume White(Color); Color := GRAY(); return true; + C: return true;}|; +{ + var colorLocal:int; + yield; + call colorLocal := GetColorNoLock(); + call YieldColorOnlyGetsDarker(); + if (White(colorLocal)) { call WriteBarrierSlow(tid); } + yield; +} + +procedure {:yields} {:layer 1,2} WriteBarrierSlow({:linear "tid"} tid:Tid) +ensures {:atomic} |{ A: assert tid != nil; goto B, C; + B: assume White(Color); Color := GRAY(); return true; + C: return true; }|; +{ + var colorLocal:int; + yield; + call AcquireLock(tid); + call colorLocal := GetColorLocked(tid); + if (White(colorLocal)) { call SetColorLocked(tid, GRAY()); } + call ReleaseLock(tid); + yield; +} + +procedure {:yields} {:layer 0,1} AcquireLock({:linear "tid"} tid: Tid); + ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; + +procedure {:yields} {:layer 0,1} ReleaseLock({:linear "tid"} tid: Tid); + ensures {:left} |{ A: assert tid != nil; assert lock == tid; lock := nil; return true; }|; + +procedure {:yields} {:layer 0,1} SetColorLocked({:linear "tid"} tid:Tid, newCol:int); + ensures {:atomic} |{A: assert tid != nil; assert lock == tid; Color := newCol; return true;}|; + +procedure {:yields} {:layer 0,1} GetColorLocked({:linear "tid"} tid:Tid) returns (col:int); + ensures {:both} |{A: assert tid != nil; assert lock == tid; col := Color; return true;}|; + +procedure {:yields} {:layer 0,2} GetColorNoLock() returns (col:int); + ensures {:atomic} |{A: col := Color; return true;}|; + + + +function {:builtin "MapConst"} MapConstBool(bool): [Tid]bool; +function {:builtin "MapOr"} MapOr([Tid]bool, [Tid]bool) : [Tid]bool; + +var {:layer 0} Color:int; +var {:layer 0} lock:Tid; + +function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool +{ + MapConstBool(false)[x := true] +} +function {:inline} {:linear "tid"} TidSetCollector(x: [Tid]bool) : [Tid]bool +{ + x +} diff --git a/Test/civl/Program5.bpl.expect b/Test/civl/Program5.bpl.expect new file mode 100644 index 00000000..d7c0ff95 --- /dev/null +++ b/Test/civl/Program5.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 18 verified, 0 errors diff --git a/Test/civl/akash.bpl b/Test/civl/akash.bpl new file mode 100644 index 00000000..c826b810 --- /dev/null +++ b/Test/civl/akash.bpl @@ -0,0 +1,106 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +function {:builtin "MapConst"} mapconstbool(bool) : [int]bool; + +function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; +function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +function {:inline} {:linear "1"} SetCollector1(x: [int]bool) : [int]bool +{ + x +} + +function {:inline} {:linear "2"} SetCollector2(x: [int]bool) : [int]bool +{ + x +} + +var {:layer 0,1} g: int; +var {:layer 0,1} h: int; + +procedure {:yields} {:layer 0,1} SetG(val:int); +ensures {:atomic} |{A: g := val; return true; }|; + +procedure {:yields} {:layer 0,1} SetH(val:int); +ensures {:atomic} |{A: h := val; return true; }|; + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: int) +ensures {:layer 1} xl != 0; +{ + yield; + call xl := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: int); +ensures {:atomic} |{ A: assume xls != 0; return true; }|; + +procedure {:yields} {:layer 1} A({:linear_in "tid"} tid_in: int, {:linear_in "1"} x: [int]bool, {:linear_in "2"} y: [int]bool) returns ({:linear "tid"} tid_out: int) +requires {:layer 1} x == mapconstbool(true); +requires {:layer 1} y == mapconstbool(true); +{ + var {:linear "tid"} tid_child: int; + tid_out := tid_in; + + yield; + call SetG(0); + yield; + assert {:layer 1} g == 0 && x == mapconstbool(true); + + yield; + call tid_child := Allocate(); + async call B(tid_child, x); + + yield; + call SetH(0); + + yield; + assert {:layer 1} h == 0 && y == mapconstbool(true); + + yield; + call tid_child := Allocate(); + async call C(tid_child, y); + + yield; +} + +procedure {:yields} {:layer 1} B({:linear_in "tid"} tid_in: int, {:linear_in "1"} x_in: [int]bool) +requires {:layer 1} x_in != mapconstbool(false); +{ + var {:linear "tid"} tid_out: int; + var {:linear "1"} x: [int]bool; + tid_out := tid_in; + x := x_in; + + yield; + + call SetG(1); + + yield; + + call SetG(2); + + yield; +} + +procedure {:yields} {:layer 1} C({:linear_in "tid"} tid_in: int, {:linear_in "2"} y_in: [int]bool) +requires {:layer 1} y_in != mapconstbool(false); +{ + var {:linear "tid"} tid_out: int; + var {:linear "2"} y: [int]bool; + tid_out := tid_in; + y := y_in; + + yield; + + call SetH(1); + + yield; + + call SetH(2); + + yield; +} \ No newline at end of file diff --git a/Test/civl/akash.bpl.expect b/Test/civl/akash.bpl.expect new file mode 100644 index 00000000..fef5ddc0 --- /dev/null +++ b/Test/civl/akash.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/civl/bar.bpl b/Test/civl/bar.bpl new file mode 100644 index 00000000..4eef8378 --- /dev/null +++ b/Test/civl/bar.bpl @@ -0,0 +1,57 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} g:int; + +procedure {:yields} {:layer 1} PB() +{ + yield; + call Incr(); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:atomic} +|{A: + g := g + 1; return true; +}|; + +procedure {:yields} {:layer 0,1} Set(v: int); +ensures {:atomic} +|{A: + g := v; return true; +}|; + +procedure {:yields} {:layer 1} PC() +ensures {:layer 1} g == old(g); +{ + yield; + assert {:layer 1} g == old(g); +} + +procedure {:yields} {:layer 1} PE() +{ + call PC(); +} + +procedure {:yields} {:layer 1} PD() +{ + yield; + call Set(3); + call PC(); + assert {:layer 1} g == 3; +} + +procedure {:yields} {:layer 1} Main2() +{ + yield; + while (*) + { + async call PB(); + yield; + async call PE(); + yield; + async call PD(); + yield; + } + yield; +} diff --git a/Test/civl/bar.bpl.expect b/Test/civl/bar.bpl.expect new file mode 100644 index 00000000..8999ae7f --- /dev/null +++ b/Test/civl/bar.bpl.expect @@ -0,0 +1,13 @@ +bar.bpl(28,3): Error: Non-interference check failed +Execution trace: + bar.bpl(7,3): anon0 + (0,0): anon00 + bar.bpl(14,3): inline$Incr_1$0$this_A + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 +bar.bpl(28,3): Error: Non-interference check failed +Execution trace: + bar.bpl(38,3): anon0 + (0,0): anon00 + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 + +Boogie program verifier finished with 3 verified, 2 errors diff --git a/Test/civl/chris.bpl b/Test/civl/chris.bpl new file mode 100644 index 00000000..b54292ef --- /dev/null +++ b/Test/civl/chris.bpl @@ -0,0 +1,28 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var{:layer 1} x:int; + +procedure{:yields}{:layer 2} Havoc() + ensures{:atomic} |{ A: return true; }|; +{ + yield; +} + +procedure{:yields}{:layer 1} Recover() + ensures{:atomic} |{ A: assert x == 5; return true; }|; +{ + yield; +} + +procedure{:yields}{:layer 3} P() + ensures{:atomic} |{ A: return true; }|; + requires{:layer 2,3} x == 5; + ensures {:layer 2,3} x == 5; +{ + + yield; assert{:layer 2,3} x == 5; + call Havoc(); + yield; assert{:layer 3} x == 5; + call Recover(); + yield; assert{:layer 2,3} x == 5; +} diff --git a/Test/civl/chris.bpl.expect b/Test/civl/chris.bpl.expect new file mode 100644 index 00000000..be6b95ba --- /dev/null +++ b/Test/civl/chris.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 6 verified, 0 errors diff --git a/Test/civl/chris2.bpl b/Test/civl/chris2.bpl new file mode 100644 index 00000000..73f112ed --- /dev/null +++ b/Test/civl/chris2.bpl @@ -0,0 +1,34 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var{:layer 20} x:int; + +procedure{:yields}{:layer 20,25} p_gt1_lower(); + ensures{:both} + |{ + A: + x := x + 1; + return true; + }|; + +procedure{:yields}{:layer 25,40} p_gt1() + ensures{:both} + |{ + A: + x := x + 1; + return true; + }|; +{ + yield; + call p_gt1_lower(); + yield; +} + +procedure{:yields}{:layer 20,40} p_gt2(); + ensures{:both} + |{ + A: + assert x == 0; + return true; + }|; + + diff --git a/Test/civl/chris2.bpl.expect b/Test/civl/chris2.bpl.expect new file mode 100644 index 00000000..2bf339f7 --- /dev/null +++ b/Test/civl/chris2.bpl.expect @@ -0,0 +1,18 @@ +(0,0): Error BP5003: A postcondition might not hold on this return path. +chris2.bpl(30,5): Related location: Gate not preserved by p_gt1_lower +Execution trace: + (0,0): this_A +(0,0): Error BP5003: A postcondition might not hold on this return path. +(0,0): Related location: Gate failure of p_gt2 not preserved by p_gt1_lower +Execution trace: + (0,0): this_A +(0,0): Error BP5003: A postcondition might not hold on this return path. +chris2.bpl(30,5): Related location: Gate not preserved by p_gt1 +Execution trace: + (0,0): this_A +(0,0): Error BP5003: A postcondition might not hold on this return path. +(0,0): Related location: Gate failure of p_gt2 not preserved by p_gt1 +Execution trace: + (0,0): this_A + +Boogie program verifier finished with 1 verified, 4 errors diff --git a/Test/civl/civl-paper.bpl b/Test/civl/civl-paper.bpl new file mode 100644 index 00000000..a7042c6a --- /dev/null +++ b/Test/civl/civl-paper.bpl @@ -0,0 +1,175 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type X; +const nil: X; + +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool +{ + MapConstBool(false)[x := true] +} + +type lmap; +function {:linear "mem"} dom(lmap): [int]bool; +function map(lmap): [int]int; +function cons([int]bool, [int]int) : lmap; +axiom (forall x: [int]bool, y: [int]int :: {cons(x,y)} dom(cons(x, y)) == x && map(cons(x,y)) == y); + +var {:layer 0,3} {:linear "mem"} g: lmap; +var {:layer 0,3} lock: X; +var {:layer 0,1} b: bool; + +const p: int; + +procedure {:yields} {:layer 1} Yield1() +requires {:layer 1} InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +{ + yield; + assert {:layer 1} InvLock(lock, b); +} + +function {:inline} InvLock(lock: X, b: bool) : bool +{ + lock != nil <==> b +} + +procedure {:yields} {:layer 2} Yield2() +{ + yield; +} + +procedure {:yields} {:layer 3} Yield3() +requires {:layer 3} Inv(g); +ensures {:layer 3} Inv(g); +{ + yield; + assert {:layer 3} Inv(g); +} + +function {:inline} Inv(g: lmap) : bool +{ + dom(g)[p] && dom(g)[p+4] && map(g)[p] == map(g)[p+4] +} + +procedure {:yields} {:layer 3} P({:linear "tid"} tid: X) +requires {:layer 1} tid != nil && InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +requires {:layer 3} tid != nil && Inv(g); +ensures {:layer 3} Inv(g); +{ + var t: int; + var {:linear "mem"} l: lmap; + + par Yield3() | Yield1(); + call AcquireProtected(tid); + call l := TransferFromGlobalProtected(tid); + call t := Load(l, p); + call l := Store(l, p, t+1); + call t := Load(l, p+4); + call l := Store(l, p+4, t+1); + call TransferToGlobalProtected(tid, l); + call ReleaseProtected(tid); + par Yield3() | Yield1(); +} + + +procedure {:yields} {:layer 2,3} TransferToGlobalProtected({:linear "tid"} tid: X, {:linear_in "mem"} l: lmap) +ensures {:both} |{ A: assert tid != nil && lock == tid; g := l; return true; }|; +requires {:layer 1} InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +{ + par Yield1() | Yield2(); + call TransferToGlobal(tid, l); + par Yield1() | Yield2(); +} + +procedure {:yields} {:layer 2,3} TransferFromGlobalProtected({:linear "tid"} tid: X) returns ({:linear "mem"} l: lmap) +ensures {:both} |{ A: assert tid != nil && lock == tid; l := g; return true; }|; +requires {:layer 1} InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +{ + par Yield1() | Yield2(); + call l := TransferFromGlobal(tid); + par Yield1() | Yield2(); +} + +procedure {:yields} {:layer 2,3} AcquireProtected({:linear "tid"} tid: X) +ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; +requires {:layer 1} tid != nil && InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +{ + par Yield1() | Yield2(); + call Acquire(tid); + par Yield1() | Yield2(); +} + +procedure {:yields} {:layer 2,3} ReleaseProtected({:linear "tid"} tid: X) +ensures {:left} |{ A: assert tid != nil && lock == tid; lock := nil; return true; }|; +requires {:layer 1} InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +{ + par Yield1() | Yield2(); + call Release(tid); + par Yield1() | Yield2(); +} + +procedure {:yields} {:layer 1,2} Acquire({:linear "tid"} tid: X) +requires {:layer 1} tid != nil && InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +ensures {:atomic} |{ A: assume lock == nil; lock := tid; return true; }|; +{ + var status: bool; + var tmp: X; + + par Yield1(); + L: + assert {:layer 1} InvLock(lock, b); + call status := CAS(tid, false, true); + par Yield1(); + goto A, B; + + A: + assume status; + par Yield1(); + return; + + B: + assume !status; + goto L; +} + +procedure {:yields} {:layer 1,2} Release({:linear "tid"} tid: X) +ensures {:atomic} |{ A: lock := nil; return true; }|; +requires {:layer 1} InvLock(lock, b); +ensures {:layer 1} InvLock(lock, b); +{ + par Yield1(); + call CLEAR(tid, false); + par Yield1(); +} + +procedure {:yields} {:layer 0,2} TransferToGlobal({:linear "tid"} tid: X, {:linear_in "mem"} l: lmap); +ensures {:atomic} |{ A: g := l; return true; }|; + +procedure {:yields} {:layer 0,2} TransferFromGlobal({:linear "tid"} tid: X) returns ({:linear "mem"} l: lmap); +ensures {:atomic} |{ A: l := g; return true; }|; + +procedure {:yields} {:layer 0,3} Load({:linear "mem"} l: lmap, a: int) returns (v: int); +ensures {:both} |{ A: v := map(l)[a]; return true; }|; + +procedure {:yields} {:layer 0,3} Store({:linear_in "mem"} l_in: lmap, a: int, v: int) returns ({:linear "mem"} l_out: lmap); +ensures {:both} |{ A: assume l_out == cons(dom(l_in), map(l_in)[a := v]); return true; }|; + +procedure {:yields} {:layer 0,1} CAS(tid: X, prev: bool, next: bool) returns (status: bool); +ensures {:atomic} |{ +A: goto B, C; +B: assume b == prev; b := next; status := true; lock := tid; return true; +C: status := false; return true; +}|; + +procedure {:yields} {:layer 0,1} CLEAR(tid: X, next: bool); +ensures {:atomic} |{ +A: b := next; lock := nil; return true; +}|; + diff --git a/Test/civl/civl-paper.bpl.expect b/Test/civl/civl-paper.bpl.expect new file mode 100644 index 00000000..4bcd03fb --- /dev/null +++ b/Test/civl/civl-paper.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 35 verified, 0 errors diff --git a/Test/civl/foo.bpl b/Test/civl/foo.bpl new file mode 100644 index 00000000..7eeab890 --- /dev/null +++ b/Test/civl/foo.bpl @@ -0,0 +1,57 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} g:int; + +procedure {:yields} {:layer 1} PB() +{ + yield; + call Incr(); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:atomic} +|{A: + g := g + 1; return true; +}|; + +procedure {:yields} {:layer 0,1} Set(v: int); +ensures {:atomic} +|{A: + g := v; return true; +}|; + +procedure {:yields} {:layer 1} PC() +ensures {:layer 1} g == 3; +{ + yield; + call Set(3); + yield; + assert {:layer 1} g == 3; +} + +procedure {:yields} {:layer 1} PE() +{ + call PC(); +} + +procedure {:yields} {:layer 1} PD() +{ + call PC(); + assert {:layer 1} g == 3; +} + +procedure {:yields} {:layer 1} Main() +{ + yield; + while (*) + { + async call PB(); + yield; + async call PE(); + yield; + async call PD(); + yield; + } + yield; +} diff --git a/Test/civl/foo.bpl.expect b/Test/civl/foo.bpl.expect new file mode 100644 index 00000000..0d9de9db --- /dev/null +++ b/Test/civl/foo.bpl.expect @@ -0,0 +1,8 @@ +foo.bpl(30,3): Error: Non-interference check failed +Execution trace: + foo.bpl(7,3): anon0 + (0,0): anon00 + foo.bpl(14,3): inline$Incr_1$0$this_A + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 + +Boogie program verifier finished with 4 verified, 1 error diff --git a/Test/civl/ghost.bpl b/Test/civl/ghost.bpl new file mode 100644 index 00000000..74d16acf --- /dev/null +++ b/Test/civl/ghost.bpl @@ -0,0 +1,46 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0} x: int; + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:right} |{ A: x := x + 1; return true; }|; + +procedure ghost(y: int) returns (z: int) +requires y == 1; +ensures z == 2; +{ + z := y + 1; +} + +procedure {:yields} {:layer 1,2} Incr2() +ensures {:right} |{ A: x := x + 2; return true; }|; +{ + var {:ghost} a: int; + var {:ghost} b: int; + + yield; + call a := ghost(1); + assert {:layer 1} a == 2; + par Incr() | Incr(); + yield; +} + +procedure ghost_0() returns (z: int) +ensures z == x; +{ + z := x; +} + +procedure {:yields} {:layer 1,2} Incr2_0() +ensures {:right} |{ A: x := x + 2; return true; }|; +{ + var {:ghost} a: int; + var {:ghost} b: int; + + yield; + call a := ghost_0(); + par Incr() | Incr(); + call b := ghost_0(); + assert {:layer 1} b == a + 2; + yield; +} diff --git a/Test/civl/ghost.bpl.expect b/Test/civl/ghost.bpl.expect new file mode 100644 index 00000000..9823d44a --- /dev/null +++ b/Test/civl/ghost.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 6 verified, 0 errors diff --git a/Test/civl/linear-set.bpl b/Test/civl/linear-set.bpl new file mode 100644 index 00000000..e481291a --- /dev/null +++ b/Test/civl/linear-set.bpl @@ -0,0 +1,105 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type X; +function {:builtin "MapConst"} MapConstInt(int) : [X]int; +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:builtin "MapOr"} MapOr([X]bool, [X]bool) : [X]bool; + +function {:inline} None() : [X]bool +{ + MapConstBool(false) +} + +function {:inline} All() : [X]bool +{ + MapConstBool(true) +} + +function {:inline} {:linear "x"} XCollector(xs: [X]bool) : [X]bool +{ + xs +} + +var {:layer 0,1} x: int; +var {:layer 0,1} l: [X]bool; + + +procedure {:yields} {:layer 1} Split({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool) +ensures {:layer 1} xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); +{ + yield; + call xls1, xls2 := SplitLow(xls); + yield; +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xls: [X]bool) +{ + yield; + call xls := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 0,1} Set(v: int); +ensures {:atomic} |{A: x := v; return true; }|; + +procedure {:yields} {:layer 0,1} Lock(tidls: [X]bool); +ensures {:atomic} |{A: assume l == None(); l := tidls; return true; }|; + +procedure {:yields} {:layer 0,1} Unlock(); +ensures {:atomic} |{A: l := None(); return true; }|; + +procedure {:yields} {:layer 0,1} SplitLow({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool); +ensures {:atomic} |{ A: assume xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); return true; }|; + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: [X]bool); +ensures {:atomic} |{ A: return true; }|; + +procedure {:yields} {:layer 1} main({:linear_in "tid"} tidls': [X]bool, {:linear_in "x"} xls': [X]bool) +requires {:layer 1} tidls' != None() && xls' == All(); +{ + var {:linear "tid"} tidls: [X]bool; + var {:linear "x"} xls: [X]bool; + var {:linear "tid"} lsChild: [X]bool; + var {:linear "x"} xls1: [X]bool; + var {:linear "x"} xls2: [X]bool; + + tidls := tidls'; + xls := xls'; + yield; + call Set(42); + yield; + assert {:layer 1} xls == All(); + assert {:layer 1} x == 42; + call xls1, xls2 := Split(xls); + call lsChild := Allocate(); + assume (lsChild != None()); + yield; + async call thread(lsChild, xls1); + call lsChild := Allocate(); + assume (lsChild != None()); + yield; + async call thread(lsChild, xls2); + yield; +} + +procedure {:yields} {:layer 1} thread({:linear_in "tid"} tidls': [X]bool, {:linear_in "x"} xls': [X]bool) +requires {:layer 1} tidls' != None() && xls' != None(); +{ + var {:linear "x"} xls: [X]bool; + var {:linear "tid"} tidls: [X]bool; + + tidls := tidls'; + xls := xls'; + + yield; + call Lock(tidls); + yield; + assert {:layer 1} tidls != None() && xls != None(); + call Set(0); + yield; + assert {:layer 1} tidls != None() && xls != None(); + assert {:layer 1} x == 0; + assert {:layer 1} tidls != None() && xls != None(); + call Unlock(); + yield; +} diff --git a/Test/civl/linear-set.bpl.expect b/Test/civl/linear-set.bpl.expect new file mode 100644 index 00000000..fef5ddc0 --- /dev/null +++ b/Test/civl/linear-set.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/civl/linear-set2.bpl b/Test/civl/linear-set2.bpl new file mode 100644 index 00000000..24d8a13a --- /dev/null +++ b/Test/civl/linear-set2.bpl @@ -0,0 +1,106 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type X; +function {:builtin "MapConst"} MapConstInt(int) : [X]int; +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:builtin "MapOr"} MapOr([X]bool, [X]bool) : [X]bool; + +function {:inline} None() : [X]bool +{ + MapConstBool(false) +} + +function {:inline} All() : [X]bool +{ + MapConstBool(true) +} + +function {:inline} {:linear "x"} XCollector(xs: [X]bool) : [X]bool +{ + xs +} + +var {:layer 0,1} x: int; +var {:layer 0,1} l: X; +const nil: X; + +procedure {:yields} {:layer 1} Split({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool) +ensures {:layer 1} xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); +{ + yield; + call xls1, xls2 := SplitLow(xls); + yield; +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xls: X) +ensures {:layer 1} xls != nil; +{ + yield; + call xls := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 0,1} Set(v: int); +ensures {:atomic} |{A: x := v; return true; }|; + +procedure {:yields} {:layer 0,1} Lock(tidls: X); +ensures {:atomic} |{A: assume l == nil; l := tidls; return true; }|; + +procedure {:yields} {:layer 0,1} Unlock(); +ensures {:atomic} |{A: l := nil; return true; }|; + +procedure {:yields} {:layer 0,1} SplitLow({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool); +ensures {:atomic} |{ A: assume xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); return true; }|; + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: X); +ensures {:atomic} |{ A: assume xls != nil; return true; }|; + +procedure {:yields} {:layer 1} main({:linear_in "tid"} tidls': X, {:linear_in "x"} xls': [X]bool) +requires {:layer 1} tidls' != nil && xls' == All(); +{ + var {:linear "tid"} tidls: X; + var {:linear "x"} xls: [X]bool; + var {:linear "tid"} lsChild: X; + var {:linear "x"} xls1: [X]bool; + var {:linear "x"} xls2: [X]bool; + + tidls := tidls'; + xls := xls'; + + yield; + call Set(42); + yield; + assert {:layer 1} xls == All(); + assert {:layer 1} x == 42; + call xls1, xls2 := Split(xls); + call lsChild := Allocate(); + yield; + async call thread(lsChild, xls1); + call lsChild := Allocate(); + yield; + async call thread(lsChild, xls2); + yield; +} + +procedure {:yields} {:layer 1} thread({:linear_in "tid"} tidls': X, {:linear_in "x"} xls': [X]bool) +requires {:layer 1} tidls' != nil && xls' != None(); +{ + var {:linear "x"} xls: [X]bool; + var {:linear "tid"} tidls: X; + + tidls := tidls'; + xls := xls'; + + yield; + call Lock(tidls); + yield; + assert {:layer 1} tidls != nil && xls != None(); + call Set(0); + yield; + assert {:layer 1} tidls != nil && xls != None(); + assert {:layer 1} x == 0; + yield; + assert {:layer 1} tidls != nil && xls != None(); + call Unlock(); + yield; +} diff --git a/Test/civl/linear-set2.bpl.expect b/Test/civl/linear-set2.bpl.expect new file mode 100644 index 00000000..fef5ddc0 --- /dev/null +++ b/Test/civl/linear-set2.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/civl/lock-introduced.bpl b/Test/civl/lock-introduced.bpl new file mode 100644 index 00000000..c9650215 --- /dev/null +++ b/Test/civl/lock-introduced.bpl @@ -0,0 +1,100 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool +{ + MapConstBool(false)[x := true] +} + +type X; +const nil: X; +var {:layer 0,2} b: bool; +var {:layer 1,3} lock: X; + +procedure {:yields} {:layer 3} Customer({:linear "tid"} tid: X) +requires {:layer 2} tid != nil; +requires {:layer 2} InvLock(lock, b); +ensures {:layer 2} InvLock(lock, b); +{ + yield; + assert {:layer 2} InvLock(lock, b); + while (*) + invariant {:layer 2} InvLock(lock, b); + { + call Enter(tid); + call Leave(tid); + yield; + assert {:layer 2} InvLock(lock, b); + } + yield; + assert {:layer 2} InvLock(lock, b); +} + +function {:inline} InvLock(lock: X, b: bool) : bool +{ + lock != nil <==> b +} + +procedure {:yields} {:layer 2,3} Enter({:linear "tid"} tid: X) +requires {:layer 2} tid != nil; +requires {:layer 2} InvLock(lock, b); +ensures {:layer 2} InvLock(lock, b); +ensures {:right} |{ A: assume lock == nil && tid != nil; lock := tid; return true; }|; +{ + yield; + assert {:layer 2} InvLock(lock, b); + call LowerEnter(tid); + yield; + assert {:layer 2} InvLock(lock, b); +} + +procedure {:yields} {:layer 2,3} Leave({:linear "tid"} tid:X) +requires {:layer 2} InvLock(lock, b); +ensures {:layer 2} InvLock(lock, b); +ensures {:atomic} |{ A: assert lock == tid && tid != nil; lock := nil; return true; }|; +{ + yield; + assert {:layer 2} InvLock(lock, b); + call LowerLeave(); + yield; + assert {:layer 2} InvLock(lock, b); +} + +procedure {:yields} {:layer 1,2} LowerEnter({:linear "tid"} tid: X) +ensures {:atomic} |{ A: assume !b; b := true; lock := tid; return true; }|; +{ + var status: bool; + yield; + L: + call status := CAS(false, true); + yield; + goto A, B; + + A: + assume status; + yield; + return; + + B: + assume !status; + goto L; +} + +procedure {:yields} {:layer 1,2} LowerLeave() +ensures {:atomic} |{ A: b := false; lock := nil; return true; }|; +{ + yield; + call SET(false); + yield; +} + +procedure {:yields} {:layer 0,1} CAS(prev: bool, next: bool) returns (status: bool); +ensures {:atomic} |{ +A: goto B, C; +B: assume b == prev; b := next; status := true; return true; +C: status := false; return true; +}|; + +procedure {:yields} {:layer 0,1} SET(next: bool); +ensures {:atomic} |{ A: b := next; return true; }|; + diff --git a/Test/civl/lock-introduced.bpl.expect b/Test/civl/lock-introduced.bpl.expect new file mode 100644 index 00000000..f62a8f46 --- /dev/null +++ b/Test/civl/lock-introduced.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 12 verified, 0 errors diff --git a/Test/civl/lock.bpl b/Test/civl/lock.bpl new file mode 100644 index 00000000..9341591f --- /dev/null +++ b/Test/civl/lock.bpl @@ -0,0 +1,57 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,2} b: bool; + +procedure {:yields} {:layer 2} main() +{ + yield; + while (*) + { + async call Customer(); + yield; + } + yield; +} + +procedure {:yields} {:layer 2} Customer() +{ + yield; + while (*) + { + call Enter(); + yield; + call Leave(); + yield; + } + yield; +} + +procedure {:yields} {:layer 1,2} Enter() +ensures {:atomic} |{ A: assume !b; b := true; return true; }|; +{ + var status: bool; + yield; + L: + call status := CAS(false, true); + yield; + goto A, B; + + A: + assume status; + yield; + return; + + B: + assume !status; + goto L; +} + +procedure {:yields} {:layer 0,2} CAS(prev: bool, next: bool) returns (status: bool); +ensures {:atomic} |{ +A: goto B, C; +B: assume b == prev; b := next; status := true; return true; +C: status := false; return true; +}|; + +procedure {:yields} {:layer 0,2} Leave(); +ensures {:atomic} |{ A: b := false; return true; }|; diff --git a/Test/civl/lock.bpl.expect b/Test/civl/lock.bpl.expect new file mode 100644 index 00000000..05d394c7 --- /dev/null +++ b/Test/civl/lock.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/civl/lock2.bpl b/Test/civl/lock2.bpl new file mode 100644 index 00000000..4809a8f5 --- /dev/null +++ b/Test/civl/lock2.bpl @@ -0,0 +1,63 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,2} b: int; + +procedure {:yields} {:layer 2} main() +{ + yield; + while (*) + { + async call Customer(); + yield; + } + yield; +} + +procedure {:yields} {:layer 2} Customer() +{ + yield; + while (*) + { + call Enter(); + yield; + call Leave(); + yield; + } + yield; +} + +procedure {:yields} {:layer 1,2} Enter() +ensures {:atomic} |{ A: assume b == 0; b := 1; return true; }|; +{ + var _old, curr: int; + yield; + while (true) { + call _old := CAS(0, 1); + yield; + if (_old == 0) { + break; + } + while (true) { + call curr := Read(); + yield; + if (curr == 0) { + break; + } + } + yield; + } + yield; +} + +procedure {:yields} {:layer 0,2} Read() returns (val: int); +ensures {:atomic} |{ A: val := b; return true; }|; + +procedure {:yields} {:layer 0,2} CAS(prev: int, next: int) returns (_old: int); +ensures {:atomic} |{ +A: _old := b; goto B, C; +B: assume _old == prev; b := next; return true; +C: assume _old != prev; return true; +}|; + +procedure {:yields} {:layer 0,2} Leave(); +ensures {:atomic} |{ A: b := 0; return true; }|; diff --git a/Test/civl/lock2.bpl.expect b/Test/civl/lock2.bpl.expect new file mode 100644 index 00000000..05d394c7 --- /dev/null +++ b/Test/civl/lock2.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/civl/multiset.bpl b/Test/civl/multiset.bpl new file mode 100644 index 00000000..7fb0a081 --- /dev/null +++ b/Test/civl/multiset.bpl @@ -0,0 +1,324 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type X; + +const unique null : int; +const unique nil: X; +const unique done: X; + +var {:layer 0} elt : [int]int; +var {:layer 0} valid : [int]bool; +var {:layer 0} lock : [int]X; +var {:layer 0} owner : [int]X; +const max : int; + +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool +{ + MapConstBool(false)[x := true] +} + +axiom (max > 0); + +procedure {:yields} {:layer 0} acquire(i : int, {:linear "tid"} tid: X); +ensures {:right} |{ A: + assert 0 <= i && i < max; + assert tid != nil && tid != done; + assume lock[i] == nil; + lock[i] := tid; + return true; + }|; + + +procedure {:yields} {:layer 0} release(i : int, {:linear "tid"} tid: X); +ensures {:left} |{ A: + assert 0 <= i && i < max; + assert lock[i] == tid; + assert tid != nil && tid != done; + lock[i] := nil; + return true; + }|; + + +procedure {:yields} {:layer 0,1} getElt(j : int, {:linear "tid"} tid: X) returns (elt_j:int); +ensures {:both} |{ A: + assert 0 <= j && j < max; + assert lock[j] == tid; + assert tid != nil && tid != done; + elt_j := elt[j]; + return true; + }|; + + +procedure {:yields} {:layer 0,1} setElt(j : int, x : int, {:linear "tid"} tid: X); +ensures {:both} |{ A: + assert x != null; + assert owner[j] == nil; + assert 0 <= j && j < max; + assert lock[j] == tid; + assert tid != nil && tid != done; + elt[j] := x; + owner[j] := tid; + return true; + }|; + + +procedure {:yields} {:layer 0,2} setEltToNull(j : int, {:linear "tid"} tid: X); +ensures {:left} |{ A: + assert owner[j] == tid; + assert 0 <= j && j < max; + assert lock[j] == tid; + assert !valid[j]; + assert tid != nil && tid != done; + elt[j] := null; + owner[j] := nil; + return true; + }|; + +procedure {:yields} {:layer 0,2} setValid(j : int, {:linear "tid"} tid: X); +ensures {:both} |{ A: + assert 0 <= j && j < max; + assert lock[j] == tid; + assert tid != nil && tid != done; + assert owner[j] == tid; + valid[j] := true; + owner[j] := done; + return true; + }|; + +procedure {:yields} {:layer 0,2} isEltThereAndValid(j : int, x : int, {:linear "tid"} tid: X) returns (fnd:bool); +ensures {:both} |{ A: + assert 0 <= j && j < max; + assert lock[j] == tid; + assert tid != nil && tid != done; + fnd := (elt[j] == x) && valid[j]; + return true; + }|; + +procedure {:yields} {:layer 1,2} FindSlot(x : int, {:linear "tid"} tid: X) returns (r : int) +requires {:layer 1} Inv(valid, elt, owner) && x != null && tid != nil && tid != done; +ensures {:layer 1} Inv(valid, elt, owner); +ensures {:right} |{ A: assert tid != nil && tid != done; + assert x != null; + goto B, C; + B: assume (0 <= r && r < max); + assume elt[r] == null; + assume owner[r] == nil; + assume !valid[r]; + elt[r] := x; + owner[r] := tid; + return true; + C: assume (r == -1); return true; + }|; +{ + var j : int; + var elt_j : int; + + par Yield1(); + + j := 0; + while(j < max) + invariant {:layer 1} Inv(valid, elt, owner); + invariant {:layer 1} 0 <= j; + { + call acquire(j, tid); + call elt_j := getElt(j, tid); + if(elt_j == null) + { + call setElt(j, x, tid); + call release(j, tid); + r := j; + + par Yield1(); + return; + } + call release(j,tid); + + par Yield1(); + + j := j + 1; + } + r := -1; + + par Yield1(); + return; +} + +procedure {:yields} {:layer 2} Insert(x : int, {:linear "tid"} tid: X) returns (result : bool) +requires {:layer 1} Inv(valid, elt, owner) && x != null && tid != nil && tid != done; +ensures {:layer 1} Inv(valid, elt, owner); +requires {:layer 2} Inv(valid, elt, owner) && x != null && tid != nil && tid != done; +ensures {:layer 2} Inv(valid, elt, owner); +ensures {:atomic} |{ var r:int; + A: goto B, C; + B: assume (0 <= r && r < max); + assume valid[r] == false; + assume elt[r] == null; + assume owner[r] == nil; + elt[r] := x; valid[r] := true; owner[r] := done; + result := true; return true; + C: result := false; return true; + }|; + { + var i: int; + par Yield12(); + call i := FindSlot(x, tid); + + if(i == -1) + { + result := false; + par Yield12(); + return; + } + par Yield1(); + assert {:layer 1} i != -1; + assert {:layer 2} i != -1; + call acquire(i, tid); + assert {:layer 2} elt[i] == x; + assert {:layer 2} valid[i] == false; + call setValid(i, tid); + call release(i, tid); + result := true; + par Yield12(); + return; +} + +procedure {:yields} {:layer 2} InsertPair(x : int, y : int, {:linear "tid"} tid: X) returns (result : bool) +requires {:layer 1} Inv(valid, elt, owner) && x != null && y != null && tid != nil && tid != done; +ensures {:layer 1} Inv(valid, elt, owner); +requires {:layer 2} Inv(valid, elt, owner) && x != null && y != null && tid != nil && tid != done; +ensures {:layer 2} Inv(valid, elt, owner); +ensures {:atomic} |{ var rx:int; + var ry:int; + A: goto B, C; + B: assume (0 <= rx && rx < max && 0 <= ry && ry < max && rx != ry); + assume valid[rx] == false; + assume valid[ry] == false; + assume elt[rx] == null; + assume elt[rx] == null; + elt[rx] := x; + elt[ry] := y; + valid[rx] := true; + valid[ry] := true; + owner[rx] := done; + owner[ry] := done; + result := true; return true; + C: result := false; return true; + }|; + { + var i : int; + var j : int; + par Yield12(); + + call i := FindSlot(x, tid); + + if (i == -1) + { + result := false; + par Yield12(); + return; + } + + par Yield1(); + call j := FindSlot(y, tid); + + if(j == -1) + { + par Yield1(); + call acquire(i,tid); + call setEltToNull(i, tid); + call release(i,tid); + result := false; + par Yield12(); + return; + } + + par Yield1(); + assert {:layer 2} i != -1 && j != -1; + call acquire(i, tid); + call acquire(j, tid); + assert {:layer 2} elt[i] == x; + assert {:layer 2} elt[j] == y; + assert {:layer 2} valid[i] == false; + assert {:layer 2} valid[j] == false; + call setValid(i, tid); + call setValid(j, tid); + call release(j, tid); + call release(i, tid); + result := true; + par Yield12(); + return; +} + +procedure {:yields} {:layer 2} LookUp(x : int, {:linear "tid"} tid: X, old_valid:[int]bool, old_elt:[int]int) returns (found : bool) +requires {:layer 1} {:layer 2} old_valid == valid && old_elt == elt; +requires {:layer 1} {:layer 2} Inv(valid, elt, owner); +requires {:layer 1} {:layer 2} (tid != nil && tid != done); +ensures {:layer 1} {:layer 2} Inv(valid, elt, owner); +ensures {:atomic} |{ A: assert tid != nil && tid != done; + assert x != null; + assume found ==> (exists ii:int :: 0 <= ii && ii < max && valid[ii] && elt[ii] == x); + assume !found ==> (forall ii:int :: 0 <= ii && ii < max ==> !(old_valid[ii] && old_elt[ii] == x)); + return true; + }|; +{ + var j : int; + var isThere : bool; + + par Yield12() | YieldLookUp(old_valid, old_elt); + + j := 0; + + while(j < max) + invariant {:layer 1} {:layer 2} Inv(valid, elt, owner); + invariant {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < j ==> !(old_valid[ii] && old_elt[ii] == x)); + invariant {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); + invariant {:layer 1} {:layer 2} 0 <= j; + { + call acquire(j, tid); + call isThere := isEltThereAndValid(j, x, tid); + if(isThere) + { + call release(j, tid); + found := true; + par Yield12() | YieldLookUp(old_valid, old_elt); + return; + } + call release(j,tid); + par Yield12() | YieldLookUp(old_valid, old_elt); + j := j + 1; + } + found := false; + + par Yield12() | YieldLookUp(old_valid, old_elt); + return; +} + +procedure {:yields} {:layer 1} Yield1() +requires {:layer 1} Inv(valid, elt, owner); +ensures {:layer 1} Inv(valid, elt, owner); +{ + yield; + assert {:layer 1} Inv(valid, elt, owner); +} + +procedure {:yields} {:layer 2} Yield12() +requires {:layer 1} {:layer 2} Inv(valid, elt, owner); +ensures {:layer 1} {:layer 2} Inv(valid, elt, owner); +{ + yield; + assert {:layer 1} {:layer 2} Inv(valid, elt, owner); +} + +function {:inline} Inv(valid: [int]bool, elt: [int]int, owner: [int]X): (bool) +{ + (forall i:int :: 0 <= i && i < max ==> (elt[i] == null <==> (!valid[i] && owner[i] == nil))) +} + +procedure {:yields} {:layer 2} YieldLookUp(old_valid: [int]bool, old_elt: [int]int) +requires {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); +ensures {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); +{ + yield; + assert {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); +} diff --git a/Test/civl/multiset.bpl.expect b/Test/civl/multiset.bpl.expect new file mode 100644 index 00000000..d72077a6 --- /dev/null +++ b/Test/civl/multiset.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 78 verified, 0 errors diff --git a/Test/civl/new1.bpl b/Test/civl/new1.bpl new file mode 100644 index 00000000..b80b6315 --- /dev/null +++ b/Test/civl/new1.bpl @@ -0,0 +1,42 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +function {:builtin "MapConst"} mapconstbool(x:bool): [int]bool; + +var {:layer 0,1} g:int; + +function {:inline} {:linear "Perm"} SetCollectorPerm(x: [int]bool) : [int]bool +{ + x +} + +procedure {:yields} {:layer 1} PB({:linear_in "Perm"} permVar_in:[int]bool) +requires {:layer 1} permVar_in[0] && g == 0; +{ + var {:linear "Perm"} permVar_out: [int]bool; + permVar_out := permVar_in; + + yield; + assert {:layer 1} permVar_out[0]; + assert {:layer 1} g == 0; + + call IncrG(); + + yield; + assert {:layer 1} permVar_out[0]; + assert {:layer 1} g == 1; +} + +procedure {:yields} {:layer 1} Main({:linear_in "Perm"} Permissions: [int]bool) +requires {:layer 1} Permissions == mapconstbool(true); +{ + yield; + call SetG(0); + async call PB(Permissions); + yield; +} + +procedure {:yields} {:layer 0,1} SetG(val:int); +ensures {:atomic} |{A: g := val; return true; }|; + +procedure {:yields} {:layer 0,1} IncrG(); +ensures {:atomic} |{A: g := g + 1; return true; }|; diff --git a/Test/civl/new1.bpl.expect b/Test/civl/new1.bpl.expect new file mode 100644 index 00000000..3de74d3e --- /dev/null +++ b/Test/civl/new1.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 2 verified, 0 errors diff --git a/Test/civl/one.bpl b/Test/civl/one.bpl new file mode 100644 index 00000000..663b2da0 --- /dev/null +++ b/Test/civl/one.bpl @@ -0,0 +1,18 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} x:int; + +procedure {:yields} {:layer 0,1} Set(v: int); +ensures {:atomic} +|{A: + x := v; return true; +}|; + +procedure {:yields} {:layer 1} B() +{ + yield; + call Set(5); + yield; + assert {:layer 1} x == 5; +} + diff --git a/Test/civl/one.bpl.expect b/Test/civl/one.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/civl/one.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/civl/par-incr.bpl b/Test/civl/par-incr.bpl new file mode 100644 index 00000000..7be8f561 --- /dev/null +++ b/Test/civl/par-incr.bpl @@ -0,0 +1,31 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +var {:layer 0} x: int; + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:right} |{ A: x := x + 1; return true; }|; + +procedure {:yields} {:layer 1,2} Incr2() +ensures {:right} |{ A: x := x + 2; return true; }|; +{ + yield; + par Incr() | Incr(); + yield; +} + +procedure {:yields} {:layer 1} Yield() +{ + yield; +} + +procedure {:yields} {:layer 2,3} Incr4() +ensures {:atomic} |{ A: x := x + 4; return true; }|; +{ + yield; + par Incr2() | Incr2() | Yield(); + yield; +} + + + diff --git a/Test/civl/par-incr.bpl.expect b/Test/civl/par-incr.bpl.expect new file mode 100644 index 00000000..00ddb38b --- /dev/null +++ b/Test/civl/par-incr.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/civl/parallel1.bpl b/Test/civl/parallel1.bpl new file mode 100644 index 00000000..20dd3c79 --- /dev/null +++ b/Test/civl/parallel1.bpl @@ -0,0 +1,48 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} g:int; + +procedure {:yields} {:layer 1} PB() +{ + yield; + call Incr(); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:atomic} +|{A: + g := g + 1; return true; +}|; + +procedure {:yields} {:layer 0,1} Set(v: int); +ensures {:atomic} +|{A: + g := v; return true; +}|; + +procedure {:yields} {:layer 1} PC() +ensures {:layer 1} g == 3; +{ + yield; + call Set(3); + yield; + assert {:layer 1} g == 3; +} + +procedure {:yields} {:layer 1} PD() +{ + call PC(); + assert {:layer 1} g == 3; + yield; +} + +procedure {:yields} {:layer 1} Main() +{ + yield; + while (*) + { + par PB() | PC() | PD(); + } + yield; +} diff --git a/Test/civl/parallel1.bpl.expect b/Test/civl/parallel1.bpl.expect new file mode 100644 index 00000000..588c9c5b --- /dev/null +++ b/Test/civl/parallel1.bpl.expect @@ -0,0 +1,8 @@ +parallel1.bpl(30,3): Error: Non-interference check failed +Execution trace: + parallel1.bpl(7,3): anon0 + (0,0): anon00 + parallel1.bpl(14,3): inline$Incr_1$0$this_A + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 + +Boogie program verifier finished with 3 verified, 1 error diff --git a/Test/civl/parallel2.bpl b/Test/civl/parallel2.bpl new file mode 100644 index 00000000..c28edf2b --- /dev/null +++ b/Test/civl/parallel2.bpl @@ -0,0 +1,59 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} a:[int]int; + +function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; +function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: int) +{ + yield; + call tid := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 0,1} Write(idx: int, val: int); +ensures {:atomic} |{A: a[idx] := val; return true; }|; + +procedure {:yields} {:layer 1} main() +{ + var {:linear "tid"} i: int; + var {:linear "tid"} j: int; + call i := Allocate(); + call j := Allocate(); + par i := t(i) | j := t(j); + par i := u(i) | j := u(j); +} + +procedure {:yields} {:layer 1} t({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) +{ + i := i'; + + yield; + call Write(i, 42); + call Yield(i); + assert {:layer 1} a[i] == 42; +} + +procedure {:yields} {:layer 1} u({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) +{ + i := i'; + + yield; + call Write(i, 42); + yield; + assert {:layer 1} a[i] == 42; +} + +procedure {:yields} {:layer 1} Yield({:linear "tid"} i: int) +ensures {:layer 1} old(a)[i] == a[i]; +{ + yield; + assert {:layer 1} old(a)[i] == a[i]; +} + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: int); +ensures {:atomic} |{ A: return true; }|; diff --git a/Test/civl/parallel2.bpl.expect b/Test/civl/parallel2.bpl.expect new file mode 100644 index 00000000..05d394c7 --- /dev/null +++ b/Test/civl/parallel2.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/civl/parallel4.bpl b/Test/civl/parallel4.bpl new file mode 100644 index 00000000..f06ff4b8 --- /dev/null +++ b/Test/civl/parallel4.bpl @@ -0,0 +1,45 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} a:int; + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: int) +{ + yield; + call tid := AllocateLow(); + yield; +} + +function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; +function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +procedure {:yields} {:layer 1} main() +{ + var {:linear "tid"} i: int; + var {:linear "tid"} j: int; + call i := Allocate(); + call j := Allocate(); + par i := t(i) | j := t(j); +} + +procedure {:yields} {:layer 1} t({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) +{ + i := i'; + call Yield(); + assert {:layer 1} a == old(a); + call Incr(); + yield; +} + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:atomic} |{A: a := a + 1; return true; }|; + +procedure {:yields} {:layer 1} Yield() +{ + yield; +} + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: int); +ensures {:atomic} |{ A: return true; }|; diff --git a/Test/civl/parallel4.bpl.expect b/Test/civl/parallel4.bpl.expect new file mode 100644 index 00000000..25ad398c --- /dev/null +++ b/Test/civl/parallel4.bpl.expect @@ -0,0 +1,6 @@ +parallel4.bpl(31,3): Error BP5001: This assertion might not hold. +Execution trace: + parallel4.bpl(29,5): anon0 + (0,0): anon01 + +Boogie program verifier finished with 3 verified, 1 error diff --git a/Test/civl/parallel5.bpl b/Test/civl/parallel5.bpl new file mode 100644 index 00000000..87afc888 --- /dev/null +++ b/Test/civl/parallel5.bpl @@ -0,0 +1,59 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} a:[int]int; + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: int) +{ + yield; + call tid := AllocateLow(); + yield; +} + +function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; +function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +procedure {:yields} {:layer 0,1} Write(idx: int, val: int); +ensures {:atomic} |{A: a[idx] := val; return true; }|; + +procedure {:yields} {:layer 1} main() +{ + var {:linear "tid"} i: int; + var {:linear "tid"} j: int; + call i := Allocate(); + call j := Allocate(); + par i := t(i) | Yield(j); + par i := u(i) | j := u(j); +} + +procedure {:yields} {:layer 1} t({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) +{ + i := i'; + + yield; + call Write(i, 42); + call Yield(i); + assert {:layer 1} a[i] == 42; +} + +procedure {:yields} {:layer 1} u({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) +{ + i := i'; + + yield; + call Write(i, 42); + yield; + assert {:layer 1} a[i] == 42; +} + +procedure {:yields} {:layer 1} Yield({:linear "tid"} i: int) +ensures {:layer 1} old(a)[i] == a[i]; +{ + yield; + assert {:layer 1} old(a)[i] == a[i]; +} + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: int); +ensures {:atomic} |{ A: return true; }|; diff --git a/Test/civl/parallel5.bpl.expect b/Test/civl/parallel5.bpl.expect new file mode 100644 index 00000000..05d394c7 --- /dev/null +++ b/Test/civl/parallel5.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/civl/perm.bpl b/Test/civl/perm.bpl new file mode 100644 index 00000000..5bc75324 --- /dev/null +++ b/Test/civl/perm.bpl @@ -0,0 +1,49 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +var {:layer 0,1} x: int; +function {:builtin "MapConst"} ch_mapconstbool(x: bool) : [int]bool; + +function {:builtin "MapOr"} ch_mapunion(x: [int]bool, y: [int]bool) : [int]bool; + +function {:inline} {:linear "Perm"} SetCollectorPerm(x: [int]bool) : [int]bool +{ + x +} + +procedure {:yields} {:layer 1} mainE({:linear_in "Perm"} permVar_in: [int]bool) + requires {:layer 1} permVar_in == ch_mapconstbool(true); + requires {:layer 1} x == 0; +{ + var {:linear "Perm"} permVar_out: [int]bool; + + permVar_out := permVar_in; + + yield; + assert {:layer 1} x == 0; + assert {:layer 1} permVar_out == ch_mapconstbool(true); + + async call foo(permVar_out); + yield; +} + +procedure {:yields} {:layer 1} foo({:linear_in "Perm"} permVar_in: [int]bool) + requires {:layer 1} permVar_in != ch_mapconstbool(false); + requires {:layer 1} permVar_in[1]; + requires {:layer 1} x == 0; +{ + var {:linear "Perm"} permVar_out: [int]bool; + permVar_out := permVar_in; + + yield; + assert {:layer 1} permVar_out[1]; + assert {:layer 1} x == 0; + + call Incr(); + + yield; + assert {:layer 1} permVar_out[1]; + assert {:layer 1} x == 1; +} + +procedure {:yields} {:layer 0,1} Incr(); +ensures {:atomic} |{A: x := x + 1; return true; }|; \ No newline at end of file diff --git a/Test/civl/perm.bpl.expect b/Test/civl/perm.bpl.expect new file mode 100644 index 00000000..3de74d3e --- /dev/null +++ b/Test/civl/perm.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 2 verified, 0 errors diff --git a/Test/civl/t1.bpl b/Test/civl/t1.bpl new file mode 100644 index 00000000..675b3842 --- /dev/null +++ b/Test/civl/t1.bpl @@ -0,0 +1,103 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +function {:builtin "MapConst"} mapconstbool(bool) : [int]bool; + +function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; +function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +function {:inline} {:linear "1"} SetCollector1(x: [int]bool) : [int]bool +{ + x +} + +function {:inline} {:linear "2"} SetCollector2(x: [int]bool) : [int]bool +{ + x +} + +var {:layer 0,1} g: int; +var {:layer 0,1} h: int; + +procedure {:yields} {:layer 0,1} SetG(val:int); +ensures {:atomic} |{A: g := val; return true; }|; + +procedure {:yields} {:layer 0,1} SetH(val:int); +ensures {:atomic} |{A: h := val; return true; }|; + +procedure {:yields} {:layer 1} Yield({:linear "1"} x: [int]bool) +requires {:layer 1} x == mapconstbool(true) && g == 0; +ensures {:layer 1} x == mapconstbool(true) && g == 0; +{ + yield; + assert {:layer 1} x == mapconstbool(true) && g == 0; +} + +procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: int) +ensures {:layer 1} xl != 0; +{ + yield; + call xl := AllocateLow(); + yield; +} + +procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: int); +ensures {:atomic} |{ A: assume xls != 0; return true; }|; + +procedure {:yields} {:layer 1} A({:linear_in "tid"} tid_in: int, {:linear_in "1"} x: [int]bool, {:linear_in "2"} y: [int]bool) returns ({:linear "tid"} tid_out: int) +requires {:layer 1} x == mapconstbool(true); +requires {:layer 1} y == mapconstbool(true); +{ + var {:linear "tid"} tid_child: int; + tid_out := tid_in; + + yield; + call SetG(0); + + par tid_child := Allocate() | Yield(x); + + async call B(tid_child, x); + + yield; + assert {:layer 1} x == mapconstbool(true); + assert {:layer 1} g == 0; + + call SetH(0); + + yield; + assert {:layer 1} h == 0 && y == mapconstbool(true); + + yield; + call tid_child := Allocate(); + async call C(tid_child, y); + + yield; +} + +procedure {:yields} {:layer 1} B({:linear_in "tid"} tid_in: int, {:linear_in "1"} x_in: [int]bool) +requires {:layer 1} x_in != mapconstbool(false); +{ + var {:linear "tid"} tid_out: int; + var {:linear "1"} x: [int]bool; + tid_out := tid_in; + x := x_in; + + yield; + call SetG(1); + yield; +} + +procedure {:yields} {:layer 1} C({:linear_in "tid"} tid_in: int, {:linear_in "2"} y_in: [int]bool) +requires {:layer 1} y_in != mapconstbool(false); +{ + var {:linear "tid"} tid_out: int; + var {:linear "2"} y: [int]bool; + tid_out := tid_in; + y := y_in; + + yield; + call SetH(1); + yield; +} diff --git a/Test/civl/t1.bpl.expect b/Test/civl/t1.bpl.expect new file mode 100644 index 00000000..0b0c936e --- /dev/null +++ b/Test/civl/t1.bpl.expect @@ -0,0 +1,9 @@ +t1.bpl(65,5): Error: Non-interference check failed +Execution trace: + t1.bpl(84,13): anon0 + (0,0): anon05 + (0,0): inline$SetG_1$0$Entry + t1.bpl(25,21): inline$SetG_1$0$this_A + (0,0): inline$Impl_YieldChecker_A_1$0$L1 + +Boogie program verifier finished with 4 verified, 1 error diff --git a/Test/civl/termination.bpl b/Test/civl/termination.bpl new file mode 100644 index 00000000..2d5542dd --- /dev/null +++ b/Test/civl/termination.bpl @@ -0,0 +1,18 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure {:yields} {:layer 0} X(); +ensures {:atomic} |{ A: return true; }|; + +procedure {:yields} {:layer 0} Y(); +ensures {:left} |{ A: return true; }|; + +procedure {:yields} {:layer 1} main() { + yield; + call X(); + while (*) + { + call Y(); + } + yield; + assert {:layer 1} true; +} diff --git a/Test/civl/termination.bpl.expect b/Test/civl/termination.bpl.expect new file mode 100644 index 00000000..d216a01d --- /dev/null +++ b/Test/civl/termination.bpl.expect @@ -0,0 +1,3 @@ +termination.bpl(9,31): Error: Implementation main fails simulation check C at layer 1. Transactions must be separated by a yield. + +1 type checking errors detected in termination.bpl diff --git a/Test/civl/termination2.bpl b/Test/civl/termination2.bpl new file mode 100644 index 00000000..840c27c1 --- /dev/null +++ b/Test/civl/termination2.bpl @@ -0,0 +1,19 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure {:yields} {:layer 0} X(); +ensures {:atomic} |{ A: return true; }|; + +procedure {:yields} {:layer 0} Y(); +ensures {:left} |{ A: return true; }|; + +procedure {:yields} {:layer 1} main() { + yield; + call X(); + while (*) + invariant {:terminates} {:layer 1} true; + { + call Y(); + } + yield; + assert {:layer 1} true; +} diff --git a/Test/civl/termination2.bpl.expect b/Test/civl/termination2.bpl.expect new file mode 100644 index 00000000..6abb715b --- /dev/null +++ b/Test/civl/termination2.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/civl/ticket.bpl b/Test/civl/ticket.bpl new file mode 100644 index 00000000..91863e1a --- /dev/null +++ b/Test/civl/ticket.bpl @@ -0,0 +1,147 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +function RightOpen(n: int) : [int]bool; +function RightClosed(n: int) : [int]bool; +axiom (forall x: int, y: int :: RightOpen(x)[y] <==> y < x); +axiom (forall x: int, y: int :: RightClosed(x)[y] <==> y <= x); + +type X; +function {:builtin "MapConst"} mapconstbool(bool): [X]bool; +const nil: X; +var {:layer 0,2} t: int; +var {:layer 0,2} s: int; +var {:layer 0,2} cs: X; +var {:layer 0,2} T: [int]bool; + +function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; +function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool +{ + MapConstBool(false)[x := true] +} +function {:inline} {:linear "tid"} TidSetCollector(x: [X]bool) : [X]bool +{ + x +} + +function {:inline} Inv1(tickets: [int]bool, ticket: int): (bool) +{ + tickets == RightOpen(ticket) +} + +function {:inline} Inv2(tickets: [int]bool, ticket: int, lock: X): (bool) +{ + if (lock == nil) then tickets == RightOpen(ticket) else tickets == RightClosed(ticket) +} + +procedure {:yields} {:layer 2} Allocate({:linear_in "tid"} xls':[X]bool) returns ({:linear "tid"} xls: [X]bool, {:linear "tid"} xl: X) +ensures {:layer 1} {:layer 2} xl != nil; +{ + yield; + call xls, xl := AllocateLow(xls'); + yield; +} + +procedure {:yields} {:layer 2} main({:linear_in "tid"} xls':[X]bool) +requires {:layer 2} xls' == mapconstbool(true); +{ + var {:linear "tid"} tid: X; + var {:linear "tid"} xls: [X]bool; + + yield; + + call Init(xls'); + xls := xls'; + + par Yield1() | Yield2(); + + while (*) + invariant {:layer 1} Inv1(T, t); + invariant {:layer 2} Inv2(T, s, cs); + { + par xls, tid := Allocate(xls) | Yield1() | Yield2(); + async call Customer(tid); + par Yield1() | Yield2(); + } + par Yield1() | Yield2(); +} + +procedure {:yields} {:layer 2} Customer({:linear_in "tid"} tid: X) +requires {:layer 1} Inv1(T, t); +requires {:layer 2} tid != nil && Inv2(T, s, cs); +{ + par Yield1() | Yield2(); + while (*) + invariant {:layer 1} Inv1(T, t); + invariant {:layer 2} Inv2(T, s, cs); + { + call Enter(tid); + par Yield1() | Yield2() | YieldSpec(tid); + call Leave(tid); + par Yield1() | Yield2(); + } + par Yield1() | Yield2(); +} + +procedure {:yields} {:layer 2} Enter({:linear "tid"} tid: X) +requires {:layer 1} Inv1(T, t); +ensures {:layer 1} Inv1(T,t); +requires {:layer 2} tid != nil && Inv2(T, s, cs); +ensures {:layer 2} Inv2(T, s, cs) && cs == tid; +{ + var m: int; + + par Yield1() | Yield2(); + call m := GetTicketAbstract(tid); + par Yield1(); + call WaitAndEnter(tid, m); + par Yield1() | Yield2() | YieldSpec(tid); +} + +procedure {:yields} {:layer 1,2} GetTicketAbstract({:linear "tid"} tid: X) returns (m: int) +requires {:layer 1} Inv1(T, t); +ensures {:layer 1} Inv1(T, t); +ensures {:right} |{ A: havoc m, t; assume !T[m]; T[m] := true; return true; }|; +{ + par Yield1(); + call m := GetTicket(tid); + par Yield1(); +} + +procedure {:yields} {:layer 2} YieldSpec({:linear "tid"} tid: X) +requires {:layer 2} tid != nil && cs == tid; +ensures {:layer 2} cs == tid; +{ + yield; + assert {:layer 2} tid != nil && cs == tid; +} + +procedure {:yields} {:layer 2} Yield2() +requires {:layer 2} Inv2(T, s, cs); +ensures {:layer 2} Inv2(T, s, cs); +{ + yield; + assert {:layer 2} Inv2(T, s, cs); +} + +procedure {:yields} {:layer 1} Yield1() +requires {:layer 1} Inv1(T, t); +ensures {:layer 1} Inv1(T,t); +{ + yield; + assert {:layer 1} Inv1(T,t); +} + +procedure {:yields} {:layer 0,2} Init({:linear "tid"} xls:[X]bool); +ensures {:atomic} |{ A: assert xls == mapconstbool(true); cs := nil; t := 0; s := 0; T := RightOpen(0); return true; }|; + +procedure {:yields} {:layer 0,1} GetTicket({:linear "tid"} tid: X) returns (m: int); +ensures {:atomic} |{ A: m := t; t := t + 1; T[m] := true; return true; }|; + +procedure {:yields} {:layer 0,2} WaitAndEnter({:linear "tid"} tid: X, m:int); +ensures {:atomic} |{ A: assume m <= s; cs := tid; return true; }|; + +procedure {:yields} {:layer 0,2} Leave({:linear "tid"} tid: X); +ensures {:atomic} |{ A: s := s + 1; cs := nil; return true; }|; + +procedure {:yields} {:layer 0,2} AllocateLow({:linear_in "tid"} xls':[X]bool) returns ({:linear "tid"} xls: [X]bool, {:linear "tid"} xl: X); +ensures {:atomic} |{ A: assume xl != nil; return true; }|; diff --git a/Test/civl/ticket.bpl.expect b/Test/civl/ticket.bpl.expect new file mode 100644 index 00000000..28c26eab --- /dev/null +++ b/Test/civl/ticket.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 16 verified, 0 errors diff --git a/Test/civl/treiber-stack.bpl b/Test/civl/treiber-stack.bpl new file mode 100644 index 00000000..e1c509ab --- /dev/null +++ b/Test/civl/treiber-stack.bpl @@ -0,0 +1,202 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type Node = int; +const unique null: Node; +type lmap; +function {:linear "Node"} dom(lmap): [Node]bool; +function map(lmap): [Node]Node; +function {:builtin "MapConst"} MapConstBool(bool) : [Node]bool; + +function EmptyLmap(): (lmap); +axiom (dom(EmptyLmap()) == MapConstBool(false)); + +function Add(x: lmap, i: Node, v: Node): (lmap); +axiom (forall x: lmap, i: Node, v: Node :: dom(Add(x, i, v)) == dom(x)[i:=true] && map(Add(x, i, v)) == map(x)[i := v]); + +function Remove(x: lmap, i: Node): (lmap); +axiom (forall x: lmap, i: Node :: dom(Remove(x, i)) == dom(x)[i:=false] && map(Remove(x, i)) == map(x)); + +procedure {:yields} {:layer 0,1} ReadTopOfStack() returns (v:Node); +ensures {:right} |{ A: assume dom(Stack)[v] || dom(Used)[v]; return true; }|; + +procedure {:yields} {:layer 0,1} Load(i:Node) returns (v:Node); +ensures {:right} |{ A: assert dom(Stack)[i] || dom(Used)[i]; goto B,C; + B: assume dom(Stack)[i]; v := map(Stack)[i]; return true; + C: assume !dom(Stack)[i]; return true; }|; + +procedure {:yields} {:layer 0,1} Store({:linear_in "Node"} l_in:lmap, i:Node, v:Node) returns ({:linear "Node"} l_out:lmap); +ensures {:both} |{ A: assert dom(l_in)[i]; l_out := Add(l_in, i, v); return true; }|; + +procedure {:yields} {:layer 0,1} TransferToStack(oldVal: Node, newVal: Node, {:linear_in "Node"} l_in:lmap) returns (r: bool, {:linear "Node"} l_out:lmap); +ensures {:atomic} |{ A: assert dom(l_in)[newVal]; + goto B,C; + B: assume oldVal == TopOfStack; TopOfStack := newVal; l_out := EmptyLmap(); Stack := Add(Stack, newVal, map(l_in)[newVal]); r := true; return true; + C: assume oldVal != TopOfStack; l_out := l_in; r := false; return true; }|; + +procedure {:yields} {:layer 0,1} TransferFromStack(oldVal: Node, newVal: Node) returns (r: bool); +ensures {:atomic} |{ A: goto B,C; + B: assume oldVal == TopOfStack; TopOfStack := newVal; Used := Add(Used, oldVal, map(Stack)[oldVal]); Stack := Remove(Stack, oldVal); r := true; return true; + C: assume oldVal != TopOfStack; r := false; return true; }|; + +var {:layer 0} TopOfStack: Node; +var {:linear "Node"} {:layer 0} Stack: lmap; + + +function {:inline} Inv(TopOfStack: Node, Stack: lmap) : (bool) +{ + BetweenSet(map(Stack), TopOfStack, null)[TopOfStack] && + Subset(BetweenSet(map(Stack), TopOfStack, null), Union(Singleton(null), dom(Stack))) +} + +var {:linear "Node"} {:layer 0} Used: lmap; + +procedure {:yields} {:layer 1} push(x: Node, {:linear_in "Node"} x_lmap: lmap) +requires {:layer 1} dom(x_lmap)[x]; +requires {:layer 1} Inv(TopOfStack, Stack); +ensures {:layer 1} Inv(TopOfStack, Stack); +ensures {:atomic} |{ A: Stack := Add(Stack, x, TopOfStack); TopOfStack := x; return true; }|; +{ + var t: Node; + var g: bool; + var {:linear "Node"} t_lmap: lmap; + + yield; + assert {:layer 1} Inv(TopOfStack, Stack); + t_lmap := x_lmap; + while (true) + invariant {:layer 1} dom(t_lmap) == dom(x_lmap); + invariant {:layer 1} Inv(TopOfStack, Stack); + { + call t := ReadTopOfStack(); + call t_lmap := Store(t_lmap, x, t); + call g, t_lmap := TransferToStack(t, x, t_lmap); + if (g) { + assert {:layer 1} map(Stack)[x] == t; + break; + } + yield; + assert {:layer 1} dom(t_lmap) == dom(x_lmap); + assert {:layer 1} Inv(TopOfStack, Stack); + } + yield; + assert {:expand} {:layer 1} Inv(TopOfStack, Stack); +} + +procedure {:yields} {:layer 1} pop() +requires {:layer 1} Inv(TopOfStack, Stack); +ensures {:layer 1} Inv(TopOfStack, Stack); +ensures {:atomic} |{ var t: Node; + A: assume TopOfStack != null; t := TopOfStack; Used := Add(Used, t, map(Stack)[t]); TopOfStack := map(Stack)[t]; Stack := Remove(Stack, t); return true; }|; +{ + var g: bool; + var x: Node; + var t: Node; + + yield; + assert {:layer 1} Inv(TopOfStack, Stack); + while (true) + invariant {:layer 1} Inv(TopOfStack, Stack); + { + call t := ReadTopOfStack(); + if (t != null) { + call x := Load(t); + call g := TransferFromStack(t, x); + if (g) { + break; + } + } + yield; + assert {:layer 1} Inv(TopOfStack, Stack); + } + yield; + assert {:layer 1} Inv(TopOfStack, Stack); +} + +function Equal([int]bool, [int]bool) returns (bool); +function Subset([int]bool, [int]bool) returns (bool); + +function Empty() returns ([int]bool); +function Singleton(int) returns ([int]bool); +function Reachable([int,int]bool, int) returns ([int]bool); +function Union([int]bool, [int]bool) returns ([int]bool); + +axiom(forall x:int :: !Empty()[x]); + +axiom(forall x:int, y:int :: {Singleton(y)[x]} Singleton(y)[x] <==> x == y); +axiom(forall y:int :: {Singleton(y)} Singleton(y)[y]); + +axiom(forall x:int, S:[int]bool, T:[int]bool :: {Union(S,T)[x]}{Union(S,T),S[x]}{Union(S,T),T[x]} Union(S,T)[x] <==> S[x] || T[x]); + +axiom(forall S:[int]bool, T:[int]bool :: {Equal(S,T)} Equal(S,T) <==> Subset(S,T) && Subset(T,S)); +axiom(forall x:int, S:[int]bool, T:[int]bool :: {S[x],Subset(S,T)}{T[x],Subset(S,T)} S[x] && Subset(S,T) ==> T[x]); +axiom(forall S:[int]bool, T:[int]bool :: {Subset(S,T)} Subset(S,T) || (exists x:int :: S[x] && !T[x])); + +//////////////////// +// Between predicate +//////////////////// +function Between(f: [int]int, x: int, y: int, z: int) returns (bool); +function Avoiding(f: [int]int, x: int, y: int, z: int) returns (bool); + + +////////////////////////// +// Between set constructor +////////////////////////// +function BetweenSet(f: [int]int, x: int, z: int) returns ([int]bool); + +//////////////////////////////////////////////////// +// axioms relating Between and BetweenSet +//////////////////////////////////////////////////// +axiom(forall f: [int]int, x: int, y: int, z: int :: {BetweenSet(f, x, z)[y]} BetweenSet(f, x, z)[y] <==> Between(f, x, y, z)); +axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, z), BetweenSet(f, x, z)} Between(f, x, y, z) ==> BetweenSet(f, x, z)[y]); +axiom(forall f: [int]int, x: int, z: int :: {BetweenSet(f, x, z)} Between(f, x, x, x)); +axiom(forall f: [int]int, x: int, z: int :: {BetweenSet(f, x, z)} Between(f, z, z, z)); + + +////////////////////////// +// Axioms for Between +////////////////////////// + +// reflexive +axiom(forall f: [int]int, x: int :: Between(f, x, x, x)); + +// step +axiom(forall f: [int]int, x: int, y: int, z: int, w:int :: {Between(f, y, z, w), f[x]} Between(f, x, f[x], f[x])); + +// reach +axiom(forall f: [int]int, x: int, y: int :: {f[x], Between(f, x, y, y)} Between(f, x, y, y) ==> x == y || Between(f, x, f[x], y)); + +// cycle +axiom(forall f: [int]int, x: int, y:int :: {f[x], Between(f, x, y, y)} f[x] == x && Between(f, x, y, y) ==> x == y); + +// sandwich +axiom(forall f: [int]int, x: int, y: int :: {Between(f, x, y, x)} Between(f, x, y, x) ==> x == y); + +// order1 +axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, y), Between(f, x, z, z)} Between(f, x, y, y) && Between(f, x, z, z) ==> Between(f, x, y, z) || Between(f, x, z, y)); + +// order2 +axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, z)} Between(f, x, y, z) ==> Between(f, x, y, y) && Between(f, y, z, z)); + +// transitive1 +axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, y), Between(f, y, z, z)} Between(f, x, y, y) && Between(f, y, z, z) ==> Between(f, x, z, z)); + +// transitive2 +axiom(forall f: [int]int, x: int, y: int, z: int, w: int :: {Between(f, x, y, z), Between(f, y, w, z)} Between(f, x, y, z) && Between(f, y, w, z) ==> Between(f, x, y, w) && Between(f, x, w, z)); + +// transitive3 +axiom(forall f: [int]int, x: int, y: int, z: int, w: int :: {Between(f, x, y, z), Between(f, x, w, y)} Between(f, x, y, z) && Between(f, x, w, y) ==> Between(f, x, w, z) && Between(f, w, y, z)); + +// This axiom is required to deal with the incompleteness of the trigger for the reflexive axiom. +// It cannot be proved using the rest of the axioms. +axiom(forall f: [int]int, u:int, x: int :: {Between(f, u, x, x)} Between(f, u, x, x) ==> Between(f, u, u, x)); + +// relation between Avoiding and Between +axiom(forall f: [int]int, x: int, y: int, z: int :: {Avoiding(f, x, y, z)} Avoiding(f, x, y, z) <==> (Between(f, x, y, z) || (Between(f, x, y, y) && !Between(f, x, z, z)))); +axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, z)} Between(f, x, y, z) <==> (Avoiding(f, x, y, z) && Avoiding(f, x, z, z))); + +// update +axiom(forall f: [int]int, u: int, v: int, x: int, p: int, q: int :: {Avoiding(f[p := q], u, v, x)} Avoiding(f[p := q], u, v, x) <==> ((Avoiding(f, u, v, p) && Avoiding(f, u, v, x)) || (Avoiding(f, u, p, x) && p != x && Avoiding(f, q, v, p) && Avoiding(f, q, v, x)))); + +axiom (forall f: [int]int, p: int, q: int, u: int, w: int :: {BetweenSet(f[p := q], u, w)} Avoiding(f, u, w, p) ==> Equal(BetweenSet(f[p := q], u, w), BetweenSet(f, u, w))); +axiom (forall f: [int]int, p: int, q: int, u: int, w: int :: {BetweenSet(f[p := q], u, w)} p != w && Avoiding(f, u, p, w) && Avoiding(f, q, w, p) ==> Equal(BetweenSet(f[p := q], u, w), Union(BetweenSet(f, u, p), BetweenSet(f, q, w)))); +axiom (forall f: [int]int, p: int, q: int, u: int, w: int :: {BetweenSet(f[p := q], u, w)} Avoiding(f, u, w, p) || (p != w && Avoiding(f, u, p, w) && Avoiding(f, q, w, p)) || Equal(BetweenSet(f[p := q], u, w), Empty())); \ No newline at end of file diff --git a/Test/civl/treiber-stack.bpl.expect b/Test/civl/treiber-stack.bpl.expect new file mode 100644 index 00000000..be6b95ba --- /dev/null +++ b/Test/civl/treiber-stack.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 6 verified, 0 errors diff --git a/Test/civl/wsq.bpl b/Test/civl/wsq.bpl new file mode 100644 index 00000000..f4964258 --- /dev/null +++ b/Test/civl/wsq.bpl @@ -0,0 +1,560 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type Tid; +const nil: Tid; + +function {:builtin "MapConst"} MapConstBool(bool) : [Tid]bool; +function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool +{ + MapConstBool(false)[x := true] +} + + + +var {:layer 0,3} H: int; +var {:layer 0,3} T: int; +var {:layer 0,3} items: [int]int; +var {:layer 0} status: [int]bool; +var {:layer 0,3} take_in_cs: bool; +var {:layer 0,3} put_in_cs: bool; +var {:layer 0,3} steal_in_cs: [Tid]bool; +var {:layer 0,3} h_ss: [Tid]int; +var {:layer 0,3} t_ss: [Tid]int; + +const IN_Q: bool; +const NOT_IN_Q: bool; +axiom IN_Q == true; +axiom NOT_IN_Q == false; + +const unique EMPTY: int; +const unique NIL: Tid; +const unique ptTid: Tid; +axiom ptTid != NIL; + +function {:inline} stealerTid(tid: Tid):(bool) { tid != NIL && tid != ptTid } + +function {:inline} ideasInv(put_in_cs:bool, + items:[int]int, + status: [int]bool, + H:int, T:int, + take_in_cs:bool, + steal_in_cs:[Tid]bool, + h_ss:[Tid]int, + t_ss:[Tid]int + ):(bool) +{ + ( + ( (take_in_cs) && h_ss[ptTid] < t_ss[ptTid] ==> (t_ss[ptTid] == T && H <= T && + items[T] != EMPTY && status[T] == IN_Q) ) && + (put_in_cs ==> !take_in_cs) && (take_in_cs ==> !put_in_cs) && + (( (take_in_cs) && H != h_ss[ptTid]) ==> H > h_ss[ptTid]) && + (forall td:Tid :: (stealerTid(td) && steal_in_cs[td] && H == h_ss[td] && H < t_ss[td]) ==> (items[H] != EMPTY && status[H] == IN_Q)) && + (forall td:Tid :: (stealerTid(td) && steal_in_cs[td] && H != h_ss[td]) ==> H > h_ss[td]) + ) +} + +function {:inline} queueInv(steal_in_cs:[Tid]bool, + put_in_cs:bool, + take_in_cs:bool, + items:[int]int, status: [int]bool, _H:int, _T:int):(bool) +{ + ( (forall i:int :: (_H <= i && i <= _T) ==> (status[i] == IN_Q && items[i] != EMPTY)) ) +} + +function {:inline} emptyInv(put_in_cs:bool, take_in_cs:bool, items:[int]int, status:[int]bool, T:int):(bool) +{ + (forall i:int :: (i>=T && !put_in_cs && !take_in_cs) ==> status[i] == NOT_IN_Q && items[i] == EMPTY) +} + +function {:inline} putInv(items:[int]int, status: [int]bool, H:int, T:int):(bool) +{ + (forall i:int :: (H <= i && i < T) ==> (status[i] == IN_Q && items[i] != EMPTY)) +} + +function {:inline} takeInv(items:[int]int, status: [int]bool, H:int, T:int, t:int, h:int):(bool) +{ + (forall i:int :: (h <= i && i <= t) ==> (status[i] == IN_Q && + items[i] != EMPTY) && + t == T + ) +} + +procedure {:yields} {:layer 3} put({:linear "tid"} tid:Tid, task: int) +requires {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && task != EMPTY && !take_in_cs && !put_in_cs; +requires {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); +requires {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); +ensures {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; +ensures {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); +ensures {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); +ensures {:atomic} |{ var i: int; A: assume status[i] == NOT_IN_Q; status[i] := IN_Q; return true; }|; +{ + var t: int; + var {:ghost} oldH:int; + var {:ghost} oldT:int; + var {:ghost} oldStatusT:bool; + + + oldH := H; + oldT := T; + yield; + assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; + assert {:layer 3} {:expand} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H && oldT == T; + assert {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); + + call t := readT_put(tid); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && put_in_cs; + assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} tid == ptTid && t == T; + assert {:layer 3} oldH <= H && oldT == T; + assert {:layer 3} (forall i:int :: i>=T ==> status[i] == NOT_IN_Q && items[i] == EMPTY); + + call writeItems_put(tid,t, task); + + oldH := H; + oldT := T; + oldStatusT := status[T]; + yield; + assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && t == T && tid == ptTid && !take_in_cs && put_in_cs; + assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} items[t] == task; + assert {:layer 3} oldH <= H && oldT == T; + assert {:layer 3} (forall i:int :: i>T ==> status[i] == NOT_IN_Q && items[i] == EMPTY); + + + call writeT_put(tid, t+1); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; + assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} T == t + 1; + assert {:layer 3} oldH <= H && oldT == T; + assert {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); +} + +procedure {:yields} {:layer 3} take({:linear "tid"} tid:Tid) returns (task: int, taskstatus: bool) +requires {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; +requires {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); +ensures {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs && (task != EMPTY ==> taskstatus == IN_Q); +ensures {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); +ensures {:atomic} |{ var i: int; A: goto B,C; B: assume status[i] == IN_Q; status[i] := NOT_IN_Q; return true; C: return true;}|; +{ + var h, t: int; + var chk: bool; + var {:ghost} oldH:int; + var {:ghost} oldT:int; + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H && oldT == T; + + LOOP_ENTRY_1: + + while(true) + invariant {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; + invariant {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + { + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H && oldT == T; + + call t := readT_take_init(tid); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} t == T; + assert {:layer 3} items[t-1] == EMPTY ==> H > t-1; + assert {:layer 3} oldH <= H && oldT == T; + + t := t-1; + call writeT_take(tid, t); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && !take_in_cs && !put_in_cs && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} t == T; + assert {:layer 3} items[t] == EMPTY ==> H > t; + assert {:layer 3} oldH <= H && oldT == T; + + call h := readH_take(tid); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && take_in_cs && !put_in_cs && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} t == T; + assert {:layer 3} h <= H; + assert {:layer 3} items[t] == EMPTY ==> H > t; + assert {:layer 3} oldH <= H; + assert {:layer 3} oldT == T; + assert {:layer 3} h <= H; + assert {:layer 3} oldH == h; + + if(t= h; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && take_in_cs && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} t == T && task == items[T]; + assert {:layer 3} T > H ==> items[T] != EMPTY; + assert {:layer 3} oldH <= H && oldT == T && !put_in_cs && take_in_cs; + + if(t>h) { + call takeExitCS(tid); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} t == T && task == items[t] && task != EMPTY && taskstatus == IN_Q; + assert {:layer 3} oldH <= H && oldT == T && !put_in_cs && !take_in_cs; + return; + } + call writeT_take_eq(tid, h+1); + oldH := H; + oldT := T; + + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} T == h + 1; + assert {:layer 3} oldH <= H; + assert {:layer 3} oldT == T; + assert {:layer 3} task == items[t]; + assert {:layer 3} !put_in_cs; + + call chk := CAS_H_take(tid, h,h+1); + + + oldH := H; + oldT := T; + yield; + assert {:layer 3} chk ==> (h+1 == oldH && h_ss[tid] == oldH -1 && task != EMPTY); + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} h+1 == T; + assert {:layer 3} task == items[t]; + assert {:layer 3} !take_in_cs; + assert {:layer 3} !put_in_cs; + assert {:layer 3} oldH <= H && oldT == T; + + if(!chk) { + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} h+1 == T && task == items[t] && !take_in_cs && !put_in_cs; + assert {:layer 3} oldH <= H && oldT == T; + + goto LOOP_ENTRY_1; + } + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} h+1 == T && task == items[t] && !take_in_cs && !put_in_cs; + assert {:layer 3} oldH <= H && oldT == T && task != EMPTY && taskstatus == IN_Q; + + return; + } + + oldH := H; + oldT := T; + yield; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && !put_in_cs; + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H && oldT == T; + +} + + +procedure {:yields}{:layer 3} steal({:linear "tid"} tid:Tid) returns (task: int, taskstatus: bool) +requires {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && stealerTid(tid) && + !steal_in_cs[tid]; +requires {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); +ensures {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && + !steal_in_cs[tid] && (task != EMPTY ==> taskstatus == IN_Q); +ensures {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); +ensures {:atomic} |{ var i: int; A: goto B,C; B: assume status[i] == IN_Q; status[i] := NOT_IN_Q; return true; C: return true;}|; +{ + var h, t: int; + var chk: bool; + var {:ghost} oldH:int; + var {:ghost} oldT:int; + + oldH := H; + oldT := T; + yield; + assert {:layer 3} stealerTid(tid); + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H; + assert {:layer 3} !steal_in_cs[tid]; + + LOOP_ENTRY_2: + while(true) + invariant {:layer 3} stealerTid(tid); + invariant {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + invariant {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + invariant {:layer 3} !steal_in_cs[tid]; + { + oldH := H; + oldT := T; + yield; + assert {:layer 3} stealerTid(tid); + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H; + assert {:layer 3} !steal_in_cs[tid]; + + call h := readH_steal(tid); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} H >= h; + assert {:layer 3} !steal_in_cs[tid]; + assert {:layer 3} h_ss[tid] == h; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H; + + call t := readT_steal(tid); + + + oldH := H; + oldT := T; + yield; + assert {:layer 3} steal_in_cs[tid]; + assert {:layer 3} stealerTid(tid) && H >= h && steal_in_cs[tid] && h_ss[tid] == h; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H && t == t_ss[tid]; + assert {:layer 3} (h < t && take_in_cs && (h_ss[ptTid] < t_ss[ptTid]) && h == H) ==> (H < T); + assert {:layer 3} H >= h; + + if( h>= t) { + + task := EMPTY; + call stealExitCS(tid); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} !steal_in_cs[tid]; + assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid] && h_ss[tid] == h; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H; + return; + } + + call task, taskstatus := readItems(tid, h); + + + oldH := H; + oldT := T; + yield; + assert {:layer 3} stealerTid(tid) && steal_in_cs[tid] && h_ss[tid] == h; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H; + assert {:layer 3} oldH == H && H == h && h_ss[tid] == h ==> task != EMPTY; + assert {:layer 3} (take_in_cs && (h_ss[ptTid] < t_ss[ptTid]) && h == H) ==> (H < T); + assert {:layer 3} h == H ==> status[H] == IN_Q; + + call chk := CAS_H_steal(tid, h,h+1); + + oldH := H; + oldT := T; + yield; + assert {:layer 3} h_ss[tid] == h; + assert {:layer 3} chk ==> (h+1 == oldH && h_ss[tid] == h && task != EMPTY && taskstatus == IN_Q); + assert {:layer 3} (take_in_cs && (h_ss[ptTid] < t_ss[ptTid]) && chk) ==> ((oldH-1) < T); + assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid]; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} oldH <= H; + + if(!chk) { + goto LOOP_ENTRY_2; + } + + oldH := H; + oldT := T; + yield; + assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid]; + assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); + assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); + assert {:layer 3} oldH <= H && task != EMPTY; + return; + } + + oldH := H; + oldT := T; + yield; + assert {:layer 3} chk && task != EMPTY; + assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid]; + assert {:layer 3} oldH <= H; +} + +procedure {:yields}{:layer 0,3} readH_take({:linear "tid"} tid:Tid) returns (y: int); +ensures {:atomic} |{A: assert tid == ptTid; + y := H; + take_in_cs := true; + h_ss[tid] := H; + return true;}|; + +procedure {:yields}{:layer 0,3} readH_steal({:linear "tid"} tid:Tid) returns (y: int); +ensures {:atomic} |{A: assert stealerTid(tid); + assert !steal_in_cs[tid]; + y := H; + h_ss[tid] := H; + return true;}|; + +procedure {:yields}{:layer 0,3} readT_take_init({:linear "tid"} tid:Tid) returns (y: int); +ensures {:atomic} |{A: assert tid != NIL; assert tid == ptTid; y := T; return true;}|; + +procedure {:yields}{:layer 0,3} readT_put({:linear "tid"} tid:Tid) returns (y: int); +ensures {:atomic} |{A: assert tid != NIL; + assert tid == ptTid; + put_in_cs := true; + y := T; + return true;}|; + +procedure {:yields}{:layer 0,3} readT_steal({:linear "tid"} tid:Tid) returns (y: int); +ensures {:atomic} |{A: assert tid != NIL; + assert stealerTid(tid); + assert !steal_in_cs[tid]; + y := T; + t_ss[tid] := T; + steal_in_cs[tid] := true; + return true;}|; + +procedure {:yields}{:layer 0,3} readItems({:linear "tid"} tid:Tid, ind: int) returns (y: int, b:bool); +ensures {:atomic} |{A: y := items[ind]; b := status[ind]; return true; }|; + +procedure {:yields}{:layer 0,3} writeT_put({:linear "tid"} tid:Tid, val: int); +ensures {:atomic} |{A: assert tid == ptTid; + T := T+1; + put_in_cs := false; + return true; }|; + +procedure {:yields}{:layer 0,3} writeT_take({:linear "tid"} tid:Tid, val: int); +ensures {:atomic} |{A: assert tid == ptTid; + T := val; + t_ss[tid] := val; + return true; }|; + +procedure {:yields}{:layer 0,3} writeT_take_abort({:linear "tid"} tid:Tid, val: int); +ensures {:atomic} |{A: assert tid == ptTid; + assert take_in_cs; + T := val; + take_in_cs := false; + return true; }|; + +procedure {:yields}{:layer 0,3} writeT_take_eq({:linear "tid"} tid:Tid, val: int); +ensures {:atomic} |{A: assert tid == ptTid; + T := val; + return true; }|; + +procedure {:yields}{:layer 0,3} takeExitCS({:linear "tid"} tid:Tid); +ensures {:atomic} |{A: assert tid == ptTid; + take_in_cs := false; + return true; }|; + +procedure {:yields}{:layer 0,3} stealExitCS({:linear "tid"} tid:Tid); +ensures {:atomic} |{A: assert stealerTid(tid); + assert steal_in_cs[tid]; + steal_in_cs[tid] := false; + return true; }|; + + +procedure {:yields}{:layer 0,3} writeItems({:linear "tid"} tid:Tid, idx: int, val: int); +ensures {:atomic} |{A: assert tid == ptTid; + assert val != EMPTY; + items[idx] := val; + status[idx] := IN_Q; + return true; }|; + + +procedure {:yields}{:layer 0,3} writeItems_put({:linear "tid"} tid:Tid, idx: int, val: int); +ensures {:atomic} |{A: assert tid == ptTid; + assert val != EMPTY; + items[idx] := val; + status[idx] := IN_Q; + return true; }|; + +procedure {:yields}{:layer 0,3} CAS_H_take({:linear "tid"} tid:Tid, prevVal :int, val: int) + returns (result: bool); +ensures {:atomic} |{ A: assert tid == ptTid; + goto B, C; + B: assume H == prevVal; + take_in_cs := false; + status[H] := NOT_IN_Q; + H := H+1; + result := true; + return true; + C: assume H != prevVal; result := false; + take_in_cs := false; + return true; +}|; + +procedure {:yields}{:layer 0,3} CAS_H_steal({:linear "tid"} tid:Tid, prevVal :int, val: int) + returns (result: bool); +ensures {:atomic} |{ A: assert stealerTid(tid); + goto B, C; + B: assume H == prevVal; + status[H] := NOT_IN_Q; + H := H+1; + result := true; + steal_in_cs[tid] := false; + return true; + C: assume H != prevVal; + result := false; + steal_in_cs[tid] := false; + return true; + }|; \ No newline at end of file diff --git a/Test/civl/wsq.bpl.expect b/Test/civl/wsq.bpl.expect new file mode 100644 index 00000000..5b2909f1 --- /dev/null +++ b/Test/civl/wsq.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/og/DeviceCache.bpl b/Test/og/DeviceCache.bpl deleted file mode 100644 index f439b607..00000000 --- a/Test/og/DeviceCache.bpl +++ /dev/null @@ -1,210 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type X; -function {:builtin "MapConst"} mapconstbool(bool): [X]bool; -const nil: X; -var {:layer 0,1} ghostLock: X; -var {:layer 0,1} lock: X; -var {:layer 0,1} currsize: int; -var {:layer 0,1} newsize: int; - -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool -{ - MapConstBool(false)[x := true] -} -function {:inline} {:linear "tid"} TidSetCollector(x: [X]bool) : [X]bool -{ - x -} - -function {:inline} Inv(ghostLock: X, currsize: int, newsize: int) : (bool) -{ - 0 <= currsize && currsize <= newsize && - (ghostLock == nil <==> currsize == newsize) -} - -procedure {:yields} {:layer 1} Yield() -requires {:layer 1} Inv(ghostLock, currsize, newsize); -ensures {:layer 1} Inv(ghostLock, currsize, newsize); -{ - yield; - assert {:layer 1} Inv(ghostLock, currsize, newsize); -} - -procedure {:yields} {:layer 1} YieldToReadCache({:linear "tid"} tid: X) -requires {:layer 1} Inv(ghostLock, currsize, newsize) && tid != nil; -ensures {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) <= currsize; -{ - yield; - assert {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) <= currsize; -} - -procedure {:yields} {:layer 1} YieldToWriteCache({:linear "tid"} tid: X) -requires {:layer 1} Inv(ghostLock, currsize, newsize) && ghostLock == tid && tid != nil; -ensures {:layer 1} Inv(ghostLock, currsize, newsize) && ghostLock == tid && old(currsize) == currsize && old(newsize) == newsize; -{ - yield; - assert {:layer 1} Inv(ghostLock, currsize, newsize) && tid != nil && ghostLock == tid && old(currsize) == currsize && old(newsize) == newsize; -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: X) -ensures {:layer 1} xl != nil; -{ - yield; - call xl := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 1} main({:linear_in "tid"} xls: [X]bool) -requires {:layer 1} xls == mapconstbool(true); -{ - var {:linear "tid"} tid: X; - - yield; - - call Init(xls); - - yield; - assert {:layer 1} Inv(ghostLock, currsize, newsize); - - while (*) - invariant {:layer 1} Inv(ghostLock, currsize, newsize); - { - par tid := Allocate() | Yield(); - yield; - assert {:layer 1} Inv(ghostLock, currsize, newsize); - async call Thread(tid); - yield; - assert {:layer 1} Inv(ghostLock, currsize, newsize); - } - yield; -} - -procedure {:yields} {:layer 1} Thread({:linear "tid"} tid: X) -requires {:layer 1} tid != nil; -requires {:layer 1} Inv(ghostLock, currsize, newsize); -{ - var start, size, bytesRead: int; - - havoc start, size; - assume (0 <= start && 0 <= size); - call bytesRead := Read(tid, start, size); -} - -procedure {:yields} {:layer 1} Read({:linear "tid"} tid: X, start : int, size : int) returns (bytesRead : int) -requires {:layer 1} tid != nil; -requires {:layer 1} 0 <= start && 0 <= size; -requires {:layer 1} Inv(ghostLock, currsize, newsize); -ensures {:layer 1} 0 <= bytesRead && bytesRead <= size; -{ - var i, tmp: int; - - par YieldToReadCache(tid); - bytesRead := size; - call acquire(tid); - call i := ReadCurrsize(tid); - call tmp := ReadNewsize(tid); - if (start + size <= i) { - call release(tid); - goto COPY_TO_BUFFER; - } else if (tmp > i) { - bytesRead := if (start <= i) then (i - start) else 0; - call release(tid); - goto COPY_TO_BUFFER; - } else { - call WriteNewsize(tid, start + size); - call release(tid); - goto READ_DEVICE; - } - -READ_DEVICE: - par YieldToWriteCache(tid); - call WriteCache(tid, start + size); - par YieldToWriteCache(tid); - call acquire(tid); - call tmp := ReadNewsize(tid); - call WriteCurrsize(tid, tmp); - call release(tid); - -COPY_TO_BUFFER: - par YieldToReadCache(tid); - call ReadCache(tid, start, bytesRead); -} - -procedure {:yields} {:layer 1} WriteCache({:linear "tid"} tid: X, index: int) -requires {:layer 1} Inv(ghostLock, currsize, newsize); -requires {:layer 1} ghostLock == tid && tid != nil; -ensures {:layer 1} ghostLock == tid; -ensures {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) == currsize && old(newsize) == newsize; -{ - var j: int; - - par YieldToWriteCache(tid); - call j := ReadCurrsize(tid); - while (j < index) - invariant {:layer 1} ghostLock == tid && currsize <= j && tid == tid; - invariant {:layer 1} Inv(ghostLock, currsize, newsize) && old(currsize) == currsize && old(newsize) == newsize; - { - par YieldToWriteCache(tid); - call WriteCacheEntry(tid, j); - j := j + 1; - } - par YieldToWriteCache(tid); -} - -procedure {:yields} {:layer 1} ReadCache({:linear "tid"} tid: X, start: int, bytesRead: int) -requires {:layer 1} Inv(ghostLock, currsize, newsize); -requires {:layer 1} tid != nil; -requires {:layer 1} 0 <= start && 0 <= bytesRead; -requires {:layer 1} (bytesRead == 0 || start + bytesRead <= currsize); -ensures {:layer 1} Inv(ghostLock, currsize, newsize); -{ - var j: int; - - par YieldToReadCache(tid); - - j := 0; - while(j < bytesRead) - invariant {:layer 1} 0 <= j; - invariant {:layer 1} bytesRead == 0 || start + bytesRead <= currsize; - invariant {:layer 1} Inv(ghostLock, currsize, newsize); - { - assert {:layer 1} start + j < currsize; - call ReadCacheEntry(tid, start + j); - j := j + 1; - par YieldToReadCache(tid); - } - - par YieldToReadCache(tid); -} - -procedure {:yields} {:layer 0,1} Init({:linear_in "tid"} xls:[X]bool); -ensures {:atomic} |{ A: assert xls == mapconstbool(true); currsize := 0; newsize := 0; lock := nil; ghostLock := nil; return true; }|; - -procedure {:yields} {:layer 0,1} ReadCurrsize({:linear "tid"} tid: X) returns (val: int); -ensures {:right} |{A: assert tid != nil; assert lock == tid || ghostLock == tid; val := currsize; return true; }|; - -procedure {:yields} {:layer 0,1} ReadNewsize({:linear "tid"} tid: X) returns (val: int); -ensures {:right} |{A: assert tid != nil; assert lock == tid || ghostLock == tid; val := newsize; return true; }|; - -procedure {:yields} {:layer 0,1} WriteNewsize({:linear "tid"} tid: X, val: int); -ensures {:atomic} |{A: assert tid != nil; assert lock == tid && ghostLock == nil; newsize := val; ghostLock := tid; return true; }|; - -procedure {:yields} {:layer 0,1} WriteCurrsize({:linear "tid"} tid: X, val: int); -ensures {:atomic} |{A: assert tid != nil; assert lock == tid && ghostLock == tid; currsize := val; ghostLock := nil; return true; }|; - -procedure {:yields} {:layer 0,1} ReadCacheEntry({:linear "tid"} tid: X, index: int); -ensures {:atomic} |{ A: assert 0 <= index && index < currsize; return true; }|; - -procedure {:yields} {:layer 0,1} WriteCacheEntry({:linear "tid"} tid: X, index: int); -ensures {:right} |{ A: assert tid != nil; assert currsize <= index && ghostLock == tid; return true; }|; - -procedure {:yields} {:layer 0,1} acquire({:linear "tid"} tid: X); -ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; - -procedure {:yields} {:layer 0,1} release({:linear "tid"} tid: X); -ensures {:left} |{ A: assert tid != nil; assert lock == tid; lock := nil; return true; }|; - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: X); -ensures {:atomic} |{ A: assume tid != nil; return true; }|; diff --git a/Test/og/DeviceCache.bpl.expect b/Test/og/DeviceCache.bpl.expect deleted file mode 100644 index 9ec7a92d..00000000 --- a/Test/og/DeviceCache.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 30 verified, 0 errors diff --git a/Test/og/FlanaganQadeer.bpl b/Test/og/FlanaganQadeer.bpl deleted file mode 100644 index 7345b5b2..00000000 --- a/Test/og/FlanaganQadeer.bpl +++ /dev/null @@ -1,75 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type X; -const nil: X; -var {:layer 0,1} l: X; -var {:layer 0,1} x: int; - -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool -{ - MapConstBool(false)[x := true] -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: X) -ensures {:layer 1} xl != nil; -{ - yield; - call xl := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 1} main() -{ - var {:linear "tid"} tid: X; - var val: int; - - yield; - while (*) - { - call tid := Allocate(); - havoc val; - async call foo(tid, val); - yield; - } - yield; -} -procedure {:yields} {:layer 0,1} Lock(tid: X); -ensures {:atomic} |{A: assume l == nil; l := tid; return true; }|; - -procedure {:yields} {:layer 0,1} Unlock(); -ensures {:atomic} |{A: l := nil; return true; }|; - -procedure {:yields} {:layer 0,1} Set(val: int); -ensures {:atomic} |{A: x := val; return true; }|; - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xl: X); -ensures {:atomic} |{ A: assume xl != nil; return true; }|; - -procedure {:yields} {:layer 1} foo({:linear_in "tid"} tid': X, val: int) -requires {:layer 1} tid' != nil; -{ - var {:linear "tid"} tid: X; - tid := tid'; - - yield; - call Lock(tid); - call tid := Yield(tid); - call Set(val); - call tid := Yield(tid); - assert {:layer 1} x == val; - call tid := Yield(tid); - call Unlock(); - yield; -} - -procedure {:yields} {:layer 1} Yield({:linear_in "tid"} tid': X) returns ({:linear "tid"} tid: X) -requires {:layer 1} tid' != nil; -ensures {:layer 1} tid == tid'; -ensures {:layer 1} old(l) == tid ==> old(l) == l && old(x) == x; -{ - tid := tid'; - yield; - assert {:layer 1} tid != nil; - assert {:layer 1} (old(l) == tid ==> old(l) == l && old(x) == x); -} \ No newline at end of file diff --git a/Test/og/FlanaganQadeer.bpl.expect b/Test/og/FlanaganQadeer.bpl.expect deleted file mode 100644 index fef5ddc0..00000000 --- a/Test/og/FlanaganQadeer.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/og/Program1.bpl b/Test/og/Program1.bpl deleted file mode 100644 index f405b92a..00000000 --- a/Test/og/Program1.bpl +++ /dev/null @@ -1,33 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} x:int; - -procedure {:yields} {:layer 1} p() -requires {:layer 1} x >= 5; -ensures {:layer 1} x >= 8; -{ - yield; - assert {:layer 1} x >= 5; - call Incr(1); - yield; - assert {:layer 1} x >= 6; - call Incr(1); - yield; - assert {:layer 1} x >= 7; - call Incr(1); - yield; - assert {:layer 1} x >= 8; -} - -procedure {:yields} {:layer 1} q() -{ - yield; - call Incr(3); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(val: int); -ensures {:atomic} -|{A: - x := x + val; return true; -}|; diff --git a/Test/og/Program1.bpl.expect b/Test/og/Program1.bpl.expect deleted file mode 100644 index 3de74d3e..00000000 --- a/Test/og/Program1.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 2 verified, 0 errors diff --git a/Test/og/Program2.bpl b/Test/og/Program2.bpl deleted file mode 100644 index 75c83c67..00000000 --- a/Test/og/Program2.bpl +++ /dev/null @@ -1,37 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} x:int; - -procedure {:yields} {:layer 1} yield_x(n: int) -requires {:layer 1} x >= n; -ensures {:layer 1} x >= n; -{ - yield; - assert {:layer 1} x >= n; -} - -procedure {:yields} {:layer 1} p() -requires {:layer 1} x >= 5; -ensures {:layer 1} x >= 8; -{ - call yield_x(5); - call Incr(1); - call yield_x(6); - call Incr(1); - call yield_x(7); - call Incr(1); - call yield_x(8); -} - -procedure {:yields} {:layer 1} q() -{ - yield; - call Incr(3); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(val: int); -ensures {:atomic} -|{A: - x := x + val; return true; -}|; diff --git a/Test/og/Program2.bpl.expect b/Test/og/Program2.bpl.expect deleted file mode 100644 index 5b2909f1..00000000 --- a/Test/og/Program2.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/og/Program3.bpl b/Test/og/Program3.bpl deleted file mode 100644 index f8c4e132..00000000 --- a/Test/og/Program3.bpl +++ /dev/null @@ -1,36 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} x:int; - -procedure {:yields} {:layer 1} yield_x() -ensures {:layer 1} x >= old(x); -{ - yield; - assert {:layer 1} x >= old(x); -} - -procedure {:yields} {:layer 1} p() -requires {:layer 1} x >= 5; -ensures {:layer 1} x >= 8; -{ - call yield_x(); - call Incr(1); - call yield_x(); - call Incr(1); - call yield_x(); - call Incr(1); - call yield_x(); -} - -procedure {:yields} {:layer 1} q() -{ - yield; - call Incr(3); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(val: int); -ensures {:atomic} -|{A: - x := x + val; return true; -}|; diff --git a/Test/og/Program3.bpl.expect b/Test/og/Program3.bpl.expect deleted file mode 100644 index 5b2909f1..00000000 --- a/Test/og/Program3.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/og/Program4.bpl b/Test/og/Program4.bpl deleted file mode 100644 index 7f2f9c44..00000000 --- a/Test/og/Program4.bpl +++ /dev/null @@ -1,68 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type Tid; -var {:layer 0,1} a:[Tid]int; - -procedure {:yields} {:layer 1} main() { - var {:linear "tid"} tid:Tid; - - yield; - while (true) { - call tid := Allocate(); - async call P(tid); - yield; - } - yield; -} - -procedure {:yields} {:layer 1} P({:linear "tid"} tid: Tid) -ensures {:layer 1} a[tid] == old(a)[tid] + 1; -{ - var t:int; - - yield; - assert {:layer 1} a[tid] == old(a)[tid]; - call t := Read(tid); - yield; - assert {:layer 1} a[tid] == t; - call Write(tid, t + 1); - yield; - assert {:layer 1} a[tid] == t + 1; -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: Tid) -{ - yield; - call tid := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 0,1} Read({:linear "tid"} tid: Tid) returns (val: int); -ensures {:atomic} -|{A: - val := a[tid]; return true; -}|; - -procedure {:yields} {:layer 0,1} Write({:linear "tid"} tid: Tid, val: int); -ensures {:atomic} -|{A: - a[tid] := val; return true; -}|; - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: Tid); -ensures {:atomic} |{ A: return true; }|; - - - -function {:builtin "MapConst"} MapConstBool(bool): [Tid]bool; -function {:builtin "MapOr"} MapOr([Tid]bool, [Tid]bool) : [Tid]bool; - -function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool -{ - MapConstBool(false)[x := true] -} -function {:inline} {:linear "tid"} TidSetCollector(x: [Tid]bool) : [Tid]bool -{ - x -} - diff --git a/Test/og/Program4.bpl.expect b/Test/og/Program4.bpl.expect deleted file mode 100644 index 5b2909f1..00000000 --- a/Test/og/Program4.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 3 verified, 0 errors diff --git a/Test/og/Program5.bpl b/Test/og/Program5.bpl deleted file mode 100644 index 7ede3124..00000000 --- a/Test/og/Program5.bpl +++ /dev/null @@ -1,79 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type Tid; -const unique nil: Tid; - -function {:inline} UNALLOC():int { 0 } -function {:inline} WHITE():int { 1 } -function {:inline} GRAY():int { 2 } -function {:inline} BLACK():int { 3 } -function {:inline} Unalloc(i:int) returns(bool) { i <= 0 } -function {:inline} White(i:int) returns(bool) { i == 1 } -function {:inline} Gray(i:int) returns(bool) { i == 2 } -function {:inline} Black(i:int) returns(bool) { i >= 3 } - -procedure {:yields} {:layer 2} YieldColorOnlyGetsDarker() -ensures {:layer 2} Color >= old(Color); -{ - yield; - assert {:layer 2} Color >= old(Color); -} - -procedure {:yields} {:layer 2,3} WriteBarrier({:linear "tid"} tid:Tid) -ensures {:atomic} |{ A: assert tid != nil; goto B, C; - B: assume White(Color); Color := GRAY(); return true; - C: return true;}|; -{ - var colorLocal:int; - yield; - call colorLocal := GetColorNoLock(); - call YieldColorOnlyGetsDarker(); - if (White(colorLocal)) { call WriteBarrierSlow(tid); } - yield; -} - -procedure {:yields} {:layer 1,2} WriteBarrierSlow({:linear "tid"} tid:Tid) -ensures {:atomic} |{ A: assert tid != nil; goto B, C; - B: assume White(Color); Color := GRAY(); return true; - C: return true; }|; -{ - var colorLocal:int; - yield; - call AcquireLock(tid); - call colorLocal := GetColorLocked(tid); - if (White(colorLocal)) { call SetColorLocked(tid, GRAY()); } - call ReleaseLock(tid); - yield; -} - -procedure {:yields} {:layer 0,1} AcquireLock({:linear "tid"} tid: Tid); - ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; - -procedure {:yields} {:layer 0,1} ReleaseLock({:linear "tid"} tid: Tid); - ensures {:left} |{ A: assert tid != nil; assert lock == tid; lock := nil; return true; }|; - -procedure {:yields} {:layer 0,1} SetColorLocked({:linear "tid"} tid:Tid, newCol:int); - ensures {:atomic} |{A: assert tid != nil; assert lock == tid; Color := newCol; return true;}|; - -procedure {:yields} {:layer 0,1} GetColorLocked({:linear "tid"} tid:Tid) returns (col:int); - ensures {:both} |{A: assert tid != nil; assert lock == tid; col := Color; return true;}|; - -procedure {:yields} {:layer 0,2} GetColorNoLock() returns (col:int); - ensures {:atomic} |{A: col := Color; return true;}|; - - - -function {:builtin "MapConst"} MapConstBool(bool): [Tid]bool; -function {:builtin "MapOr"} MapOr([Tid]bool, [Tid]bool) : [Tid]bool; - -var {:layer 0} Color:int; -var {:layer 0} lock:Tid; - -function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool -{ - MapConstBool(false)[x := true] -} -function {:inline} {:linear "tid"} TidSetCollector(x: [Tid]bool) : [Tid]bool -{ - x -} diff --git a/Test/og/Program5.bpl.expect b/Test/og/Program5.bpl.expect deleted file mode 100644 index d7c0ff95..00000000 --- a/Test/og/Program5.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 18 verified, 0 errors diff --git a/Test/og/akash.bpl b/Test/og/akash.bpl deleted file mode 100644 index c826b810..00000000 --- a/Test/og/akash.bpl +++ /dev/null @@ -1,106 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -function {:builtin "MapConst"} mapconstbool(bool) : [int]bool; - -function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; -function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool -{ - MapConstBool(false)[x := true] -} - -function {:inline} {:linear "1"} SetCollector1(x: [int]bool) : [int]bool -{ - x -} - -function {:inline} {:linear "2"} SetCollector2(x: [int]bool) : [int]bool -{ - x -} - -var {:layer 0,1} g: int; -var {:layer 0,1} h: int; - -procedure {:yields} {:layer 0,1} SetG(val:int); -ensures {:atomic} |{A: g := val; return true; }|; - -procedure {:yields} {:layer 0,1} SetH(val:int); -ensures {:atomic} |{A: h := val; return true; }|; - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: int) -ensures {:layer 1} xl != 0; -{ - yield; - call xl := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: int); -ensures {:atomic} |{ A: assume xls != 0; return true; }|; - -procedure {:yields} {:layer 1} A({:linear_in "tid"} tid_in: int, {:linear_in "1"} x: [int]bool, {:linear_in "2"} y: [int]bool) returns ({:linear "tid"} tid_out: int) -requires {:layer 1} x == mapconstbool(true); -requires {:layer 1} y == mapconstbool(true); -{ - var {:linear "tid"} tid_child: int; - tid_out := tid_in; - - yield; - call SetG(0); - yield; - assert {:layer 1} g == 0 && x == mapconstbool(true); - - yield; - call tid_child := Allocate(); - async call B(tid_child, x); - - yield; - call SetH(0); - - yield; - assert {:layer 1} h == 0 && y == mapconstbool(true); - - yield; - call tid_child := Allocate(); - async call C(tid_child, y); - - yield; -} - -procedure {:yields} {:layer 1} B({:linear_in "tid"} tid_in: int, {:linear_in "1"} x_in: [int]bool) -requires {:layer 1} x_in != mapconstbool(false); -{ - var {:linear "tid"} tid_out: int; - var {:linear "1"} x: [int]bool; - tid_out := tid_in; - x := x_in; - - yield; - - call SetG(1); - - yield; - - call SetG(2); - - yield; -} - -procedure {:yields} {:layer 1} C({:linear_in "tid"} tid_in: int, {:linear_in "2"} y_in: [int]bool) -requires {:layer 1} y_in != mapconstbool(false); -{ - var {:linear "tid"} tid_out: int; - var {:linear "2"} y: [int]bool; - tid_out := tid_in; - y := y_in; - - yield; - - call SetH(1); - - yield; - - call SetH(2); - - yield; -} \ No newline at end of file diff --git a/Test/og/akash.bpl.expect b/Test/og/akash.bpl.expect deleted file mode 100644 index fef5ddc0..00000000 --- a/Test/og/akash.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/og/bar.bpl b/Test/og/bar.bpl deleted file mode 100644 index 4eef8378..00000000 --- a/Test/og/bar.bpl +++ /dev/null @@ -1,57 +0,0 @@ -// RUN: %boogie -noinfer "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} g:int; - -procedure {:yields} {:layer 1} PB() -{ - yield; - call Incr(); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:atomic} -|{A: - g := g + 1; return true; -}|; - -procedure {:yields} {:layer 0,1} Set(v: int); -ensures {:atomic} -|{A: - g := v; return true; -}|; - -procedure {:yields} {:layer 1} PC() -ensures {:layer 1} g == old(g); -{ - yield; - assert {:layer 1} g == old(g); -} - -procedure {:yields} {:layer 1} PE() -{ - call PC(); -} - -procedure {:yields} {:layer 1} PD() -{ - yield; - call Set(3); - call PC(); - assert {:layer 1} g == 3; -} - -procedure {:yields} {:layer 1} Main2() -{ - yield; - while (*) - { - async call PB(); - yield; - async call PE(); - yield; - async call PD(); - yield; - } - yield; -} diff --git a/Test/og/bar.bpl.expect b/Test/og/bar.bpl.expect deleted file mode 100644 index 8999ae7f..00000000 --- a/Test/og/bar.bpl.expect +++ /dev/null @@ -1,13 +0,0 @@ -bar.bpl(28,3): Error: Non-interference check failed -Execution trace: - bar.bpl(7,3): anon0 - (0,0): anon00 - bar.bpl(14,3): inline$Incr_1$0$this_A - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 -bar.bpl(28,3): Error: Non-interference check failed -Execution trace: - bar.bpl(38,3): anon0 - (0,0): anon00 - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 - -Boogie program verifier finished with 3 verified, 2 errors diff --git a/Test/og/chris.bpl b/Test/og/chris.bpl deleted file mode 100644 index b54292ef..00000000 --- a/Test/og/chris.bpl +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var{:layer 1} x:int; - -procedure{:yields}{:layer 2} Havoc() - ensures{:atomic} |{ A: return true; }|; -{ - yield; -} - -procedure{:yields}{:layer 1} Recover() - ensures{:atomic} |{ A: assert x == 5; return true; }|; -{ - yield; -} - -procedure{:yields}{:layer 3} P() - ensures{:atomic} |{ A: return true; }|; - requires{:layer 2,3} x == 5; - ensures {:layer 2,3} x == 5; -{ - - yield; assert{:layer 2,3} x == 5; - call Havoc(); - yield; assert{:layer 3} x == 5; - call Recover(); - yield; assert{:layer 2,3} x == 5; -} diff --git a/Test/og/chris.bpl.expect b/Test/og/chris.bpl.expect deleted file mode 100644 index be6b95ba..00000000 --- a/Test/og/chris.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 6 verified, 0 errors diff --git a/Test/og/chris2.bpl b/Test/og/chris2.bpl deleted file mode 100644 index 73f112ed..00000000 --- a/Test/og/chris2.bpl +++ /dev/null @@ -1,34 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var{:layer 20} x:int; - -procedure{:yields}{:layer 20,25} p_gt1_lower(); - ensures{:both} - |{ - A: - x := x + 1; - return true; - }|; - -procedure{:yields}{:layer 25,40} p_gt1() - ensures{:both} - |{ - A: - x := x + 1; - return true; - }|; -{ - yield; - call p_gt1_lower(); - yield; -} - -procedure{:yields}{:layer 20,40} p_gt2(); - ensures{:both} - |{ - A: - assert x == 0; - return true; - }|; - - diff --git a/Test/og/chris2.bpl.expect b/Test/og/chris2.bpl.expect deleted file mode 100644 index 2bf339f7..00000000 --- a/Test/og/chris2.bpl.expect +++ /dev/null @@ -1,18 +0,0 @@ -(0,0): Error BP5003: A postcondition might not hold on this return path. -chris2.bpl(30,5): Related location: Gate not preserved by p_gt1_lower -Execution trace: - (0,0): this_A -(0,0): Error BP5003: A postcondition might not hold on this return path. -(0,0): Related location: Gate failure of p_gt2 not preserved by p_gt1_lower -Execution trace: - (0,0): this_A -(0,0): Error BP5003: A postcondition might not hold on this return path. -chris2.bpl(30,5): Related location: Gate not preserved by p_gt1 -Execution trace: - (0,0): this_A -(0,0): Error BP5003: A postcondition might not hold on this return path. -(0,0): Related location: Gate failure of p_gt2 not preserved by p_gt1 -Execution trace: - (0,0): this_A - -Boogie program verifier finished with 1 verified, 4 errors diff --git a/Test/og/civl-paper.bpl b/Test/og/civl-paper.bpl deleted file mode 100644 index a7042c6a..00000000 --- a/Test/og/civl-paper.bpl +++ /dev/null @@ -1,175 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type X; -const nil: X; - -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool -{ - MapConstBool(false)[x := true] -} - -type lmap; -function {:linear "mem"} dom(lmap): [int]bool; -function map(lmap): [int]int; -function cons([int]bool, [int]int) : lmap; -axiom (forall x: [int]bool, y: [int]int :: {cons(x,y)} dom(cons(x, y)) == x && map(cons(x,y)) == y); - -var {:layer 0,3} {:linear "mem"} g: lmap; -var {:layer 0,3} lock: X; -var {:layer 0,1} b: bool; - -const p: int; - -procedure {:yields} {:layer 1} Yield1() -requires {:layer 1} InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -{ - yield; - assert {:layer 1} InvLock(lock, b); -} - -function {:inline} InvLock(lock: X, b: bool) : bool -{ - lock != nil <==> b -} - -procedure {:yields} {:layer 2} Yield2() -{ - yield; -} - -procedure {:yields} {:layer 3} Yield3() -requires {:layer 3} Inv(g); -ensures {:layer 3} Inv(g); -{ - yield; - assert {:layer 3} Inv(g); -} - -function {:inline} Inv(g: lmap) : bool -{ - dom(g)[p] && dom(g)[p+4] && map(g)[p] == map(g)[p+4] -} - -procedure {:yields} {:layer 3} P({:linear "tid"} tid: X) -requires {:layer 1} tid != nil && InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -requires {:layer 3} tid != nil && Inv(g); -ensures {:layer 3} Inv(g); -{ - var t: int; - var {:linear "mem"} l: lmap; - - par Yield3() | Yield1(); - call AcquireProtected(tid); - call l := TransferFromGlobalProtected(tid); - call t := Load(l, p); - call l := Store(l, p, t+1); - call t := Load(l, p+4); - call l := Store(l, p+4, t+1); - call TransferToGlobalProtected(tid, l); - call ReleaseProtected(tid); - par Yield3() | Yield1(); -} - - -procedure {:yields} {:layer 2,3} TransferToGlobalProtected({:linear "tid"} tid: X, {:linear_in "mem"} l: lmap) -ensures {:both} |{ A: assert tid != nil && lock == tid; g := l; return true; }|; -requires {:layer 1} InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -{ - par Yield1() | Yield2(); - call TransferToGlobal(tid, l); - par Yield1() | Yield2(); -} - -procedure {:yields} {:layer 2,3} TransferFromGlobalProtected({:linear "tid"} tid: X) returns ({:linear "mem"} l: lmap) -ensures {:both} |{ A: assert tid != nil && lock == tid; l := g; return true; }|; -requires {:layer 1} InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -{ - par Yield1() | Yield2(); - call l := TransferFromGlobal(tid); - par Yield1() | Yield2(); -} - -procedure {:yields} {:layer 2,3} AcquireProtected({:linear "tid"} tid: X) -ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; -requires {:layer 1} tid != nil && InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -{ - par Yield1() | Yield2(); - call Acquire(tid); - par Yield1() | Yield2(); -} - -procedure {:yields} {:layer 2,3} ReleaseProtected({:linear "tid"} tid: X) -ensures {:left} |{ A: assert tid != nil && lock == tid; lock := nil; return true; }|; -requires {:layer 1} InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -{ - par Yield1() | Yield2(); - call Release(tid); - par Yield1() | Yield2(); -} - -procedure {:yields} {:layer 1,2} Acquire({:linear "tid"} tid: X) -requires {:layer 1} tid != nil && InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -ensures {:atomic} |{ A: assume lock == nil; lock := tid; return true; }|; -{ - var status: bool; - var tmp: X; - - par Yield1(); - L: - assert {:layer 1} InvLock(lock, b); - call status := CAS(tid, false, true); - par Yield1(); - goto A, B; - - A: - assume status; - par Yield1(); - return; - - B: - assume !status; - goto L; -} - -procedure {:yields} {:layer 1,2} Release({:linear "tid"} tid: X) -ensures {:atomic} |{ A: lock := nil; return true; }|; -requires {:layer 1} InvLock(lock, b); -ensures {:layer 1} InvLock(lock, b); -{ - par Yield1(); - call CLEAR(tid, false); - par Yield1(); -} - -procedure {:yields} {:layer 0,2} TransferToGlobal({:linear "tid"} tid: X, {:linear_in "mem"} l: lmap); -ensures {:atomic} |{ A: g := l; return true; }|; - -procedure {:yields} {:layer 0,2} TransferFromGlobal({:linear "tid"} tid: X) returns ({:linear "mem"} l: lmap); -ensures {:atomic} |{ A: l := g; return true; }|; - -procedure {:yields} {:layer 0,3} Load({:linear "mem"} l: lmap, a: int) returns (v: int); -ensures {:both} |{ A: v := map(l)[a]; return true; }|; - -procedure {:yields} {:layer 0,3} Store({:linear_in "mem"} l_in: lmap, a: int, v: int) returns ({:linear "mem"} l_out: lmap); -ensures {:both} |{ A: assume l_out == cons(dom(l_in), map(l_in)[a := v]); return true; }|; - -procedure {:yields} {:layer 0,1} CAS(tid: X, prev: bool, next: bool) returns (status: bool); -ensures {:atomic} |{ -A: goto B, C; -B: assume b == prev; b := next; status := true; lock := tid; return true; -C: status := false; return true; -}|; - -procedure {:yields} {:layer 0,1} CLEAR(tid: X, next: bool); -ensures {:atomic} |{ -A: b := next; lock := nil; return true; -}|; - diff --git a/Test/og/civl-paper.bpl.expect b/Test/og/civl-paper.bpl.expect deleted file mode 100644 index 4bcd03fb..00000000 --- a/Test/og/civl-paper.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 35 verified, 0 errors diff --git a/Test/og/foo.bpl b/Test/og/foo.bpl deleted file mode 100644 index 7eeab890..00000000 --- a/Test/og/foo.bpl +++ /dev/null @@ -1,57 +0,0 @@ -// RUN: %boogie -noinfer "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} g:int; - -procedure {:yields} {:layer 1} PB() -{ - yield; - call Incr(); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:atomic} -|{A: - g := g + 1; return true; -}|; - -procedure {:yields} {:layer 0,1} Set(v: int); -ensures {:atomic} -|{A: - g := v; return true; -}|; - -procedure {:yields} {:layer 1} PC() -ensures {:layer 1} g == 3; -{ - yield; - call Set(3); - yield; - assert {:layer 1} g == 3; -} - -procedure {:yields} {:layer 1} PE() -{ - call PC(); -} - -procedure {:yields} {:layer 1} PD() -{ - call PC(); - assert {:layer 1} g == 3; -} - -procedure {:yields} {:layer 1} Main() -{ - yield; - while (*) - { - async call PB(); - yield; - async call PE(); - yield; - async call PD(); - yield; - } - yield; -} diff --git a/Test/og/foo.bpl.expect b/Test/og/foo.bpl.expect deleted file mode 100644 index 0d9de9db..00000000 --- a/Test/og/foo.bpl.expect +++ /dev/null @@ -1,8 +0,0 @@ -foo.bpl(30,3): Error: Non-interference check failed -Execution trace: - foo.bpl(7,3): anon0 - (0,0): anon00 - foo.bpl(14,3): inline$Incr_1$0$this_A - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 - -Boogie program verifier finished with 4 verified, 1 error diff --git a/Test/og/ghost.bpl b/Test/og/ghost.bpl deleted file mode 100644 index 74d16acf..00000000 --- a/Test/og/ghost.bpl +++ /dev/null @@ -1,46 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0} x: int; - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:right} |{ A: x := x + 1; return true; }|; - -procedure ghost(y: int) returns (z: int) -requires y == 1; -ensures z == 2; -{ - z := y + 1; -} - -procedure {:yields} {:layer 1,2} Incr2() -ensures {:right} |{ A: x := x + 2; return true; }|; -{ - var {:ghost} a: int; - var {:ghost} b: int; - - yield; - call a := ghost(1); - assert {:layer 1} a == 2; - par Incr() | Incr(); - yield; -} - -procedure ghost_0() returns (z: int) -ensures z == x; -{ - z := x; -} - -procedure {:yields} {:layer 1,2} Incr2_0() -ensures {:right} |{ A: x := x + 2; return true; }|; -{ - var {:ghost} a: int; - var {:ghost} b: int; - - yield; - call a := ghost_0(); - par Incr() | Incr(); - call b := ghost_0(); - assert {:layer 1} b == a + 2; - yield; -} diff --git a/Test/og/ghost.bpl.expect b/Test/og/ghost.bpl.expect deleted file mode 100644 index 9823d44a..00000000 --- a/Test/og/ghost.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 6 verified, 0 errors diff --git a/Test/og/linear-set.bpl b/Test/og/linear-set.bpl deleted file mode 100644 index e481291a..00000000 --- a/Test/og/linear-set.bpl +++ /dev/null @@ -1,105 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type X; -function {:builtin "MapConst"} MapConstInt(int) : [X]int; -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:builtin "MapOr"} MapOr([X]bool, [X]bool) : [X]bool; - -function {:inline} None() : [X]bool -{ - MapConstBool(false) -} - -function {:inline} All() : [X]bool -{ - MapConstBool(true) -} - -function {:inline} {:linear "x"} XCollector(xs: [X]bool) : [X]bool -{ - xs -} - -var {:layer 0,1} x: int; -var {:layer 0,1} l: [X]bool; - - -procedure {:yields} {:layer 1} Split({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool) -ensures {:layer 1} xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); -{ - yield; - call xls1, xls2 := SplitLow(xls); - yield; -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xls: [X]bool) -{ - yield; - call xls := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 0,1} Set(v: int); -ensures {:atomic} |{A: x := v; return true; }|; - -procedure {:yields} {:layer 0,1} Lock(tidls: [X]bool); -ensures {:atomic} |{A: assume l == None(); l := tidls; return true; }|; - -procedure {:yields} {:layer 0,1} Unlock(); -ensures {:atomic} |{A: l := None(); return true; }|; - -procedure {:yields} {:layer 0,1} SplitLow({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool); -ensures {:atomic} |{ A: assume xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); return true; }|; - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: [X]bool); -ensures {:atomic} |{ A: return true; }|; - -procedure {:yields} {:layer 1} main({:linear_in "tid"} tidls': [X]bool, {:linear_in "x"} xls': [X]bool) -requires {:layer 1} tidls' != None() && xls' == All(); -{ - var {:linear "tid"} tidls: [X]bool; - var {:linear "x"} xls: [X]bool; - var {:linear "tid"} lsChild: [X]bool; - var {:linear "x"} xls1: [X]bool; - var {:linear "x"} xls2: [X]bool; - - tidls := tidls'; - xls := xls'; - yield; - call Set(42); - yield; - assert {:layer 1} xls == All(); - assert {:layer 1} x == 42; - call xls1, xls2 := Split(xls); - call lsChild := Allocate(); - assume (lsChild != None()); - yield; - async call thread(lsChild, xls1); - call lsChild := Allocate(); - assume (lsChild != None()); - yield; - async call thread(lsChild, xls2); - yield; -} - -procedure {:yields} {:layer 1} thread({:linear_in "tid"} tidls': [X]bool, {:linear_in "x"} xls': [X]bool) -requires {:layer 1} tidls' != None() && xls' != None(); -{ - var {:linear "x"} xls: [X]bool; - var {:linear "tid"} tidls: [X]bool; - - tidls := tidls'; - xls := xls'; - - yield; - call Lock(tidls); - yield; - assert {:layer 1} tidls != None() && xls != None(); - call Set(0); - yield; - assert {:layer 1} tidls != None() && xls != None(); - assert {:layer 1} x == 0; - assert {:layer 1} tidls != None() && xls != None(); - call Unlock(); - yield; -} diff --git a/Test/og/linear-set.bpl.expect b/Test/og/linear-set.bpl.expect deleted file mode 100644 index fef5ddc0..00000000 --- a/Test/og/linear-set.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/og/linear-set2.bpl b/Test/og/linear-set2.bpl deleted file mode 100644 index 24d8a13a..00000000 --- a/Test/og/linear-set2.bpl +++ /dev/null @@ -1,106 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type X; -function {:builtin "MapConst"} MapConstInt(int) : [X]int; -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:builtin "MapOr"} MapOr([X]bool, [X]bool) : [X]bool; - -function {:inline} None() : [X]bool -{ - MapConstBool(false) -} - -function {:inline} All() : [X]bool -{ - MapConstBool(true) -} - -function {:inline} {:linear "x"} XCollector(xs: [X]bool) : [X]bool -{ - xs -} - -var {:layer 0,1} x: int; -var {:layer 0,1} l: X; -const nil: X; - -procedure {:yields} {:layer 1} Split({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool) -ensures {:layer 1} xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); -{ - yield; - call xls1, xls2 := SplitLow(xls); - yield; -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xls: X) -ensures {:layer 1} xls != nil; -{ - yield; - call xls := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 0,1} Set(v: int); -ensures {:atomic} |{A: x := v; return true; }|; - -procedure {:yields} {:layer 0,1} Lock(tidls: X); -ensures {:atomic} |{A: assume l == nil; l := tidls; return true; }|; - -procedure {:yields} {:layer 0,1} Unlock(); -ensures {:atomic} |{A: l := nil; return true; }|; - -procedure {:yields} {:layer 0,1} SplitLow({:linear_in "x"} xls: [X]bool) returns ({:linear "x"} xls1: [X]bool, {:linear "x"} xls2: [X]bool); -ensures {:atomic} |{ A: assume xls == MapOr(xls1, xls2) && xls1 != None() && xls2 != None(); return true; }|; - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: X); -ensures {:atomic} |{ A: assume xls != nil; return true; }|; - -procedure {:yields} {:layer 1} main({:linear_in "tid"} tidls': X, {:linear_in "x"} xls': [X]bool) -requires {:layer 1} tidls' != nil && xls' == All(); -{ - var {:linear "tid"} tidls: X; - var {:linear "x"} xls: [X]bool; - var {:linear "tid"} lsChild: X; - var {:linear "x"} xls1: [X]bool; - var {:linear "x"} xls2: [X]bool; - - tidls := tidls'; - xls := xls'; - - yield; - call Set(42); - yield; - assert {:layer 1} xls == All(); - assert {:layer 1} x == 42; - call xls1, xls2 := Split(xls); - call lsChild := Allocate(); - yield; - async call thread(lsChild, xls1); - call lsChild := Allocate(); - yield; - async call thread(lsChild, xls2); - yield; -} - -procedure {:yields} {:layer 1} thread({:linear_in "tid"} tidls': X, {:linear_in "x"} xls': [X]bool) -requires {:layer 1} tidls' != nil && xls' != None(); -{ - var {:linear "x"} xls: [X]bool; - var {:linear "tid"} tidls: X; - - tidls := tidls'; - xls := xls'; - - yield; - call Lock(tidls); - yield; - assert {:layer 1} tidls != nil && xls != None(); - call Set(0); - yield; - assert {:layer 1} tidls != nil && xls != None(); - assert {:layer 1} x == 0; - yield; - assert {:layer 1} tidls != nil && xls != None(); - call Unlock(); - yield; -} diff --git a/Test/og/linear-set2.bpl.expect b/Test/og/linear-set2.bpl.expect deleted file mode 100644 index fef5ddc0..00000000 --- a/Test/og/linear-set2.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/og/lock-introduced.bpl b/Test/og/lock-introduced.bpl deleted file mode 100644 index c9650215..00000000 --- a/Test/og/lock-introduced.bpl +++ /dev/null @@ -1,100 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool -{ - MapConstBool(false)[x := true] -} - -type X; -const nil: X; -var {:layer 0,2} b: bool; -var {:layer 1,3} lock: X; - -procedure {:yields} {:layer 3} Customer({:linear "tid"} tid: X) -requires {:layer 2} tid != nil; -requires {:layer 2} InvLock(lock, b); -ensures {:layer 2} InvLock(lock, b); -{ - yield; - assert {:layer 2} InvLock(lock, b); - while (*) - invariant {:layer 2} InvLock(lock, b); - { - call Enter(tid); - call Leave(tid); - yield; - assert {:layer 2} InvLock(lock, b); - } - yield; - assert {:layer 2} InvLock(lock, b); -} - -function {:inline} InvLock(lock: X, b: bool) : bool -{ - lock != nil <==> b -} - -procedure {:yields} {:layer 2,3} Enter({:linear "tid"} tid: X) -requires {:layer 2} tid != nil; -requires {:layer 2} InvLock(lock, b); -ensures {:layer 2} InvLock(lock, b); -ensures {:right} |{ A: assume lock == nil && tid != nil; lock := tid; return true; }|; -{ - yield; - assert {:layer 2} InvLock(lock, b); - call LowerEnter(tid); - yield; - assert {:layer 2} InvLock(lock, b); -} - -procedure {:yields} {:layer 2,3} Leave({:linear "tid"} tid:X) -requires {:layer 2} InvLock(lock, b); -ensures {:layer 2} InvLock(lock, b); -ensures {:atomic} |{ A: assert lock == tid && tid != nil; lock := nil; return true; }|; -{ - yield; - assert {:layer 2} InvLock(lock, b); - call LowerLeave(); - yield; - assert {:layer 2} InvLock(lock, b); -} - -procedure {:yields} {:layer 1,2} LowerEnter({:linear "tid"} tid: X) -ensures {:atomic} |{ A: assume !b; b := true; lock := tid; return true; }|; -{ - var status: bool; - yield; - L: - call status := CAS(false, true); - yield; - goto A, B; - - A: - assume status; - yield; - return; - - B: - assume !status; - goto L; -} - -procedure {:yields} {:layer 1,2} LowerLeave() -ensures {:atomic} |{ A: b := false; lock := nil; return true; }|; -{ - yield; - call SET(false); - yield; -} - -procedure {:yields} {:layer 0,1} CAS(prev: bool, next: bool) returns (status: bool); -ensures {:atomic} |{ -A: goto B, C; -B: assume b == prev; b := next; status := true; return true; -C: status := false; return true; -}|; - -procedure {:yields} {:layer 0,1} SET(next: bool); -ensures {:atomic} |{ A: b := next; return true; }|; - diff --git a/Test/og/lock-introduced.bpl.expect b/Test/og/lock-introduced.bpl.expect deleted file mode 100644 index f62a8f46..00000000 --- a/Test/og/lock-introduced.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 12 verified, 0 errors diff --git a/Test/og/lock.bpl b/Test/og/lock.bpl deleted file mode 100644 index 9341591f..00000000 --- a/Test/og/lock.bpl +++ /dev/null @@ -1,57 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,2} b: bool; - -procedure {:yields} {:layer 2} main() -{ - yield; - while (*) - { - async call Customer(); - yield; - } - yield; -} - -procedure {:yields} {:layer 2} Customer() -{ - yield; - while (*) - { - call Enter(); - yield; - call Leave(); - yield; - } - yield; -} - -procedure {:yields} {:layer 1,2} Enter() -ensures {:atomic} |{ A: assume !b; b := true; return true; }|; -{ - var status: bool; - yield; - L: - call status := CAS(false, true); - yield; - goto A, B; - - A: - assume status; - yield; - return; - - B: - assume !status; - goto L; -} - -procedure {:yields} {:layer 0,2} CAS(prev: bool, next: bool) returns (status: bool); -ensures {:atomic} |{ -A: goto B, C; -B: assume b == prev; b := next; status := true; return true; -C: status := false; return true; -}|; - -procedure {:yields} {:layer 0,2} Leave(); -ensures {:atomic} |{ A: b := false; return true; }|; diff --git a/Test/og/lock.bpl.expect b/Test/og/lock.bpl.expect deleted file mode 100644 index 05d394c7..00000000 --- a/Test/og/lock.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/og/lock2.bpl b/Test/og/lock2.bpl deleted file mode 100644 index 4809a8f5..00000000 --- a/Test/og/lock2.bpl +++ /dev/null @@ -1,63 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,2} b: int; - -procedure {:yields} {:layer 2} main() -{ - yield; - while (*) - { - async call Customer(); - yield; - } - yield; -} - -procedure {:yields} {:layer 2} Customer() -{ - yield; - while (*) - { - call Enter(); - yield; - call Leave(); - yield; - } - yield; -} - -procedure {:yields} {:layer 1,2} Enter() -ensures {:atomic} |{ A: assume b == 0; b := 1; return true; }|; -{ - var _old, curr: int; - yield; - while (true) { - call _old := CAS(0, 1); - yield; - if (_old == 0) { - break; - } - while (true) { - call curr := Read(); - yield; - if (curr == 0) { - break; - } - } - yield; - } - yield; -} - -procedure {:yields} {:layer 0,2} Read() returns (val: int); -ensures {:atomic} |{ A: val := b; return true; }|; - -procedure {:yields} {:layer 0,2} CAS(prev: int, next: int) returns (_old: int); -ensures {:atomic} |{ -A: _old := b; goto B, C; -B: assume _old == prev; b := next; return true; -C: assume _old != prev; return true; -}|; - -procedure {:yields} {:layer 0,2} Leave(); -ensures {:atomic} |{ A: b := 0; return true; }|; diff --git a/Test/og/lock2.bpl.expect b/Test/og/lock2.bpl.expect deleted file mode 100644 index 05d394c7..00000000 --- a/Test/og/lock2.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/og/multiset.bpl b/Test/og/multiset.bpl deleted file mode 100644 index 7fb0a081..00000000 --- a/Test/og/multiset.bpl +++ /dev/null @@ -1,324 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type X; - -const unique null : int; -const unique nil: X; -const unique done: X; - -var {:layer 0} elt : [int]int; -var {:layer 0} valid : [int]bool; -var {:layer 0} lock : [int]X; -var {:layer 0} owner : [int]X; -const max : int; - -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool -{ - MapConstBool(false)[x := true] -} - -axiom (max > 0); - -procedure {:yields} {:layer 0} acquire(i : int, {:linear "tid"} tid: X); -ensures {:right} |{ A: - assert 0 <= i && i < max; - assert tid != nil && tid != done; - assume lock[i] == nil; - lock[i] := tid; - return true; - }|; - - -procedure {:yields} {:layer 0} release(i : int, {:linear "tid"} tid: X); -ensures {:left} |{ A: - assert 0 <= i && i < max; - assert lock[i] == tid; - assert tid != nil && tid != done; - lock[i] := nil; - return true; - }|; - - -procedure {:yields} {:layer 0,1} getElt(j : int, {:linear "tid"} tid: X) returns (elt_j:int); -ensures {:both} |{ A: - assert 0 <= j && j < max; - assert lock[j] == tid; - assert tid != nil && tid != done; - elt_j := elt[j]; - return true; - }|; - - -procedure {:yields} {:layer 0,1} setElt(j : int, x : int, {:linear "tid"} tid: X); -ensures {:both} |{ A: - assert x != null; - assert owner[j] == nil; - assert 0 <= j && j < max; - assert lock[j] == tid; - assert tid != nil && tid != done; - elt[j] := x; - owner[j] := tid; - return true; - }|; - - -procedure {:yields} {:layer 0,2} setEltToNull(j : int, {:linear "tid"} tid: X); -ensures {:left} |{ A: - assert owner[j] == tid; - assert 0 <= j && j < max; - assert lock[j] == tid; - assert !valid[j]; - assert tid != nil && tid != done; - elt[j] := null; - owner[j] := nil; - return true; - }|; - -procedure {:yields} {:layer 0,2} setValid(j : int, {:linear "tid"} tid: X); -ensures {:both} |{ A: - assert 0 <= j && j < max; - assert lock[j] == tid; - assert tid != nil && tid != done; - assert owner[j] == tid; - valid[j] := true; - owner[j] := done; - return true; - }|; - -procedure {:yields} {:layer 0,2} isEltThereAndValid(j : int, x : int, {:linear "tid"} tid: X) returns (fnd:bool); -ensures {:both} |{ A: - assert 0 <= j && j < max; - assert lock[j] == tid; - assert tid != nil && tid != done; - fnd := (elt[j] == x) && valid[j]; - return true; - }|; - -procedure {:yields} {:layer 1,2} FindSlot(x : int, {:linear "tid"} tid: X) returns (r : int) -requires {:layer 1} Inv(valid, elt, owner) && x != null && tid != nil && tid != done; -ensures {:layer 1} Inv(valid, elt, owner); -ensures {:right} |{ A: assert tid != nil && tid != done; - assert x != null; - goto B, C; - B: assume (0 <= r && r < max); - assume elt[r] == null; - assume owner[r] == nil; - assume !valid[r]; - elt[r] := x; - owner[r] := tid; - return true; - C: assume (r == -1); return true; - }|; -{ - var j : int; - var elt_j : int; - - par Yield1(); - - j := 0; - while(j < max) - invariant {:layer 1} Inv(valid, elt, owner); - invariant {:layer 1} 0 <= j; - { - call acquire(j, tid); - call elt_j := getElt(j, tid); - if(elt_j == null) - { - call setElt(j, x, tid); - call release(j, tid); - r := j; - - par Yield1(); - return; - } - call release(j,tid); - - par Yield1(); - - j := j + 1; - } - r := -1; - - par Yield1(); - return; -} - -procedure {:yields} {:layer 2} Insert(x : int, {:linear "tid"} tid: X) returns (result : bool) -requires {:layer 1} Inv(valid, elt, owner) && x != null && tid != nil && tid != done; -ensures {:layer 1} Inv(valid, elt, owner); -requires {:layer 2} Inv(valid, elt, owner) && x != null && tid != nil && tid != done; -ensures {:layer 2} Inv(valid, elt, owner); -ensures {:atomic} |{ var r:int; - A: goto B, C; - B: assume (0 <= r && r < max); - assume valid[r] == false; - assume elt[r] == null; - assume owner[r] == nil; - elt[r] := x; valid[r] := true; owner[r] := done; - result := true; return true; - C: result := false; return true; - }|; - { - var i: int; - par Yield12(); - call i := FindSlot(x, tid); - - if(i == -1) - { - result := false; - par Yield12(); - return; - } - par Yield1(); - assert {:layer 1} i != -1; - assert {:layer 2} i != -1; - call acquire(i, tid); - assert {:layer 2} elt[i] == x; - assert {:layer 2} valid[i] == false; - call setValid(i, tid); - call release(i, tid); - result := true; - par Yield12(); - return; -} - -procedure {:yields} {:layer 2} InsertPair(x : int, y : int, {:linear "tid"} tid: X) returns (result : bool) -requires {:layer 1} Inv(valid, elt, owner) && x != null && y != null && tid != nil && tid != done; -ensures {:layer 1} Inv(valid, elt, owner); -requires {:layer 2} Inv(valid, elt, owner) && x != null && y != null && tid != nil && tid != done; -ensures {:layer 2} Inv(valid, elt, owner); -ensures {:atomic} |{ var rx:int; - var ry:int; - A: goto B, C; - B: assume (0 <= rx && rx < max && 0 <= ry && ry < max && rx != ry); - assume valid[rx] == false; - assume valid[ry] == false; - assume elt[rx] == null; - assume elt[rx] == null; - elt[rx] := x; - elt[ry] := y; - valid[rx] := true; - valid[ry] := true; - owner[rx] := done; - owner[ry] := done; - result := true; return true; - C: result := false; return true; - }|; - { - var i : int; - var j : int; - par Yield12(); - - call i := FindSlot(x, tid); - - if (i == -1) - { - result := false; - par Yield12(); - return; - } - - par Yield1(); - call j := FindSlot(y, tid); - - if(j == -1) - { - par Yield1(); - call acquire(i,tid); - call setEltToNull(i, tid); - call release(i,tid); - result := false; - par Yield12(); - return; - } - - par Yield1(); - assert {:layer 2} i != -1 && j != -1; - call acquire(i, tid); - call acquire(j, tid); - assert {:layer 2} elt[i] == x; - assert {:layer 2} elt[j] == y; - assert {:layer 2} valid[i] == false; - assert {:layer 2} valid[j] == false; - call setValid(i, tid); - call setValid(j, tid); - call release(j, tid); - call release(i, tid); - result := true; - par Yield12(); - return; -} - -procedure {:yields} {:layer 2} LookUp(x : int, {:linear "tid"} tid: X, old_valid:[int]bool, old_elt:[int]int) returns (found : bool) -requires {:layer 1} {:layer 2} old_valid == valid && old_elt == elt; -requires {:layer 1} {:layer 2} Inv(valid, elt, owner); -requires {:layer 1} {:layer 2} (tid != nil && tid != done); -ensures {:layer 1} {:layer 2} Inv(valid, elt, owner); -ensures {:atomic} |{ A: assert tid != nil && tid != done; - assert x != null; - assume found ==> (exists ii:int :: 0 <= ii && ii < max && valid[ii] && elt[ii] == x); - assume !found ==> (forall ii:int :: 0 <= ii && ii < max ==> !(old_valid[ii] && old_elt[ii] == x)); - return true; - }|; -{ - var j : int; - var isThere : bool; - - par Yield12() | YieldLookUp(old_valid, old_elt); - - j := 0; - - while(j < max) - invariant {:layer 1} {:layer 2} Inv(valid, elt, owner); - invariant {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < j ==> !(old_valid[ii] && old_elt[ii] == x)); - invariant {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); - invariant {:layer 1} {:layer 2} 0 <= j; - { - call acquire(j, tid); - call isThere := isEltThereAndValid(j, x, tid); - if(isThere) - { - call release(j, tid); - found := true; - par Yield12() | YieldLookUp(old_valid, old_elt); - return; - } - call release(j,tid); - par Yield12() | YieldLookUp(old_valid, old_elt); - j := j + 1; - } - found := false; - - par Yield12() | YieldLookUp(old_valid, old_elt); - return; -} - -procedure {:yields} {:layer 1} Yield1() -requires {:layer 1} Inv(valid, elt, owner); -ensures {:layer 1} Inv(valid, elt, owner); -{ - yield; - assert {:layer 1} Inv(valid, elt, owner); -} - -procedure {:yields} {:layer 2} Yield12() -requires {:layer 1} {:layer 2} Inv(valid, elt, owner); -ensures {:layer 1} {:layer 2} Inv(valid, elt, owner); -{ - yield; - assert {:layer 1} {:layer 2} Inv(valid, elt, owner); -} - -function {:inline} Inv(valid: [int]bool, elt: [int]int, owner: [int]X): (bool) -{ - (forall i:int :: 0 <= i && i < max ==> (elt[i] == null <==> (!valid[i] && owner[i] == nil))) -} - -procedure {:yields} {:layer 2} YieldLookUp(old_valid: [int]bool, old_elt: [int]int) -requires {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); -ensures {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); -{ - yield; - assert {:layer 1} {:layer 2} (forall ii:int :: 0 <= ii && ii < max && old_valid[ii] ==> valid[ii] && old_elt[ii] == elt[ii]); -} diff --git a/Test/og/multiset.bpl.expect b/Test/og/multiset.bpl.expect deleted file mode 100644 index d72077a6..00000000 --- a/Test/og/multiset.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 78 verified, 0 errors diff --git a/Test/og/new1.bpl b/Test/og/new1.bpl deleted file mode 100644 index b80b6315..00000000 --- a/Test/og/new1.bpl +++ /dev/null @@ -1,42 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -function {:builtin "MapConst"} mapconstbool(x:bool): [int]bool; - -var {:layer 0,1} g:int; - -function {:inline} {:linear "Perm"} SetCollectorPerm(x: [int]bool) : [int]bool -{ - x -} - -procedure {:yields} {:layer 1} PB({:linear_in "Perm"} permVar_in:[int]bool) -requires {:layer 1} permVar_in[0] && g == 0; -{ - var {:linear "Perm"} permVar_out: [int]bool; - permVar_out := permVar_in; - - yield; - assert {:layer 1} permVar_out[0]; - assert {:layer 1} g == 0; - - call IncrG(); - - yield; - assert {:layer 1} permVar_out[0]; - assert {:layer 1} g == 1; -} - -procedure {:yields} {:layer 1} Main({:linear_in "Perm"} Permissions: [int]bool) -requires {:layer 1} Permissions == mapconstbool(true); -{ - yield; - call SetG(0); - async call PB(Permissions); - yield; -} - -procedure {:yields} {:layer 0,1} SetG(val:int); -ensures {:atomic} |{A: g := val; return true; }|; - -procedure {:yields} {:layer 0,1} IncrG(); -ensures {:atomic} |{A: g := g + 1; return true; }|; diff --git a/Test/og/new1.bpl.expect b/Test/og/new1.bpl.expect deleted file mode 100644 index 3de74d3e..00000000 --- a/Test/og/new1.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 2 verified, 0 errors diff --git a/Test/og/one.bpl b/Test/og/one.bpl deleted file mode 100644 index 663b2da0..00000000 --- a/Test/og/one.bpl +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %boogie -noinfer "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} x:int; - -procedure {:yields} {:layer 0,1} Set(v: int); -ensures {:atomic} -|{A: - x := v; return true; -}|; - -procedure {:yields} {:layer 1} B() -{ - yield; - call Set(5); - yield; - assert {:layer 1} x == 5; -} - diff --git a/Test/og/one.bpl.expect b/Test/og/one.bpl.expect deleted file mode 100644 index 6abb715b..00000000 --- a/Test/og/one.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/og/par-incr.bpl b/Test/og/par-incr.bpl deleted file mode 100644 index 7be8f561..00000000 --- a/Test/og/par-incr.bpl +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" - -var {:layer 0} x: int; - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:right} |{ A: x := x + 1; return true; }|; - -procedure {:yields} {:layer 1,2} Incr2() -ensures {:right} |{ A: x := x + 2; return true; }|; -{ - yield; - par Incr() | Incr(); - yield; -} - -procedure {:yields} {:layer 1} Yield() -{ - yield; -} - -procedure {:yields} {:layer 2,3} Incr4() -ensures {:atomic} |{ A: x := x + 4; return true; }|; -{ - yield; - par Incr2() | Incr2() | Yield(); - yield; -} - - - diff --git a/Test/og/par-incr.bpl.expect b/Test/og/par-incr.bpl.expect deleted file mode 100644 index 00ddb38b..00000000 --- a/Test/og/par-incr.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 4 verified, 0 errors diff --git a/Test/og/parallel1.bpl b/Test/og/parallel1.bpl deleted file mode 100644 index 20dd3c79..00000000 --- a/Test/og/parallel1.bpl +++ /dev/null @@ -1,48 +0,0 @@ -// RUN: %boogie -noinfer "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} g:int; - -procedure {:yields} {:layer 1} PB() -{ - yield; - call Incr(); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:atomic} -|{A: - g := g + 1; return true; -}|; - -procedure {:yields} {:layer 0,1} Set(v: int); -ensures {:atomic} -|{A: - g := v; return true; -}|; - -procedure {:yields} {:layer 1} PC() -ensures {:layer 1} g == 3; -{ - yield; - call Set(3); - yield; - assert {:layer 1} g == 3; -} - -procedure {:yields} {:layer 1} PD() -{ - call PC(); - assert {:layer 1} g == 3; - yield; -} - -procedure {:yields} {:layer 1} Main() -{ - yield; - while (*) - { - par PB() | PC() | PD(); - } - yield; -} diff --git a/Test/og/parallel1.bpl.expect b/Test/og/parallel1.bpl.expect deleted file mode 100644 index 588c9c5b..00000000 --- a/Test/og/parallel1.bpl.expect +++ /dev/null @@ -1,8 +0,0 @@ -parallel1.bpl(30,3): Error: Non-interference check failed -Execution trace: - parallel1.bpl(7,3): anon0 - (0,0): anon00 - parallel1.bpl(14,3): inline$Incr_1$0$this_A - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 - -Boogie program verifier finished with 3 verified, 1 error diff --git a/Test/og/parallel2.bpl b/Test/og/parallel2.bpl deleted file mode 100644 index c28edf2b..00000000 --- a/Test/og/parallel2.bpl +++ /dev/null @@ -1,59 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} a:[int]int; - -function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; -function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool -{ - MapConstBool(false)[x := true] -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: int) -{ - yield; - call tid := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 0,1} Write(idx: int, val: int); -ensures {:atomic} |{A: a[idx] := val; return true; }|; - -procedure {:yields} {:layer 1} main() -{ - var {:linear "tid"} i: int; - var {:linear "tid"} j: int; - call i := Allocate(); - call j := Allocate(); - par i := t(i) | j := t(j); - par i := u(i) | j := u(j); -} - -procedure {:yields} {:layer 1} t({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) -{ - i := i'; - - yield; - call Write(i, 42); - call Yield(i); - assert {:layer 1} a[i] == 42; -} - -procedure {:yields} {:layer 1} u({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) -{ - i := i'; - - yield; - call Write(i, 42); - yield; - assert {:layer 1} a[i] == 42; -} - -procedure {:yields} {:layer 1} Yield({:linear "tid"} i: int) -ensures {:layer 1} old(a)[i] == a[i]; -{ - yield; - assert {:layer 1} old(a)[i] == a[i]; -} - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: int); -ensures {:atomic} |{ A: return true; }|; diff --git a/Test/og/parallel2.bpl.expect b/Test/og/parallel2.bpl.expect deleted file mode 100644 index 05d394c7..00000000 --- a/Test/og/parallel2.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/og/parallel4.bpl b/Test/og/parallel4.bpl deleted file mode 100644 index f06ff4b8..00000000 --- a/Test/og/parallel4.bpl +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} a:int; - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: int) -{ - yield; - call tid := AllocateLow(); - yield; -} - -function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; -function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool -{ - MapConstBool(false)[x := true] -} - -procedure {:yields} {:layer 1} main() -{ - var {:linear "tid"} i: int; - var {:linear "tid"} j: int; - call i := Allocate(); - call j := Allocate(); - par i := t(i) | j := t(j); -} - -procedure {:yields} {:layer 1} t({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) -{ - i := i'; - call Yield(); - assert {:layer 1} a == old(a); - call Incr(); - yield; -} - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:atomic} |{A: a := a + 1; return true; }|; - -procedure {:yields} {:layer 1} Yield() -{ - yield; -} - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: int); -ensures {:atomic} |{ A: return true; }|; diff --git a/Test/og/parallel4.bpl.expect b/Test/og/parallel4.bpl.expect deleted file mode 100644 index 25ad398c..00000000 --- a/Test/og/parallel4.bpl.expect +++ /dev/null @@ -1,6 +0,0 @@ -parallel4.bpl(31,3): Error BP5001: This assertion might not hold. -Execution trace: - parallel4.bpl(29,5): anon0 - (0,0): anon01 - -Boogie program verifier finished with 3 verified, 1 error diff --git a/Test/og/parallel5.bpl b/Test/og/parallel5.bpl deleted file mode 100644 index 87afc888..00000000 --- a/Test/og/parallel5.bpl +++ /dev/null @@ -1,59 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} a:[int]int; - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} tid: int) -{ - yield; - call tid := AllocateLow(); - yield; -} - -function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; -function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool -{ - MapConstBool(false)[x := true] -} - -procedure {:yields} {:layer 0,1} Write(idx: int, val: int); -ensures {:atomic} |{A: a[idx] := val; return true; }|; - -procedure {:yields} {:layer 1} main() -{ - var {:linear "tid"} i: int; - var {:linear "tid"} j: int; - call i := Allocate(); - call j := Allocate(); - par i := t(i) | Yield(j); - par i := u(i) | j := u(j); -} - -procedure {:yields} {:layer 1} t({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) -{ - i := i'; - - yield; - call Write(i, 42); - call Yield(i); - assert {:layer 1} a[i] == 42; -} - -procedure {:yields} {:layer 1} u({:linear_in "tid"} i': int) returns ({:linear "tid"} i: int) -{ - i := i'; - - yield; - call Write(i, 42); - yield; - assert {:layer 1} a[i] == 42; -} - -procedure {:yields} {:layer 1} Yield({:linear "tid"} i: int) -ensures {:layer 1} old(a)[i] == a[i]; -{ - yield; - assert {:layer 1} old(a)[i] == a[i]; -} - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} tid: int); -ensures {:atomic} |{ A: return true; }|; diff --git a/Test/og/parallel5.bpl.expect b/Test/og/parallel5.bpl.expect deleted file mode 100644 index 05d394c7..00000000 --- a/Test/og/parallel5.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 5 verified, 0 errors diff --git a/Test/og/perm.bpl b/Test/og/perm.bpl deleted file mode 100644 index 5bc75324..00000000 --- a/Test/og/perm.bpl +++ /dev/null @@ -1,49 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -var {:layer 0,1} x: int; -function {:builtin "MapConst"} ch_mapconstbool(x: bool) : [int]bool; - -function {:builtin "MapOr"} ch_mapunion(x: [int]bool, y: [int]bool) : [int]bool; - -function {:inline} {:linear "Perm"} SetCollectorPerm(x: [int]bool) : [int]bool -{ - x -} - -procedure {:yields} {:layer 1} mainE({:linear_in "Perm"} permVar_in: [int]bool) - requires {:layer 1} permVar_in == ch_mapconstbool(true); - requires {:layer 1} x == 0; -{ - var {:linear "Perm"} permVar_out: [int]bool; - - permVar_out := permVar_in; - - yield; - assert {:layer 1} x == 0; - assert {:layer 1} permVar_out == ch_mapconstbool(true); - - async call foo(permVar_out); - yield; -} - -procedure {:yields} {:layer 1} foo({:linear_in "Perm"} permVar_in: [int]bool) - requires {:layer 1} permVar_in != ch_mapconstbool(false); - requires {:layer 1} permVar_in[1]; - requires {:layer 1} x == 0; -{ - var {:linear "Perm"} permVar_out: [int]bool; - permVar_out := permVar_in; - - yield; - assert {:layer 1} permVar_out[1]; - assert {:layer 1} x == 0; - - call Incr(); - - yield; - assert {:layer 1} permVar_out[1]; - assert {:layer 1} x == 1; -} - -procedure {:yields} {:layer 0,1} Incr(); -ensures {:atomic} |{A: x := x + 1; return true; }|; \ No newline at end of file diff --git a/Test/og/perm.bpl.expect b/Test/og/perm.bpl.expect deleted file mode 100644 index 3de74d3e..00000000 --- a/Test/og/perm.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 2 verified, 0 errors diff --git a/Test/og/t1.bpl b/Test/og/t1.bpl deleted file mode 100644 index 675b3842..00000000 --- a/Test/og/t1.bpl +++ /dev/null @@ -1,103 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -function {:builtin "MapConst"} mapconstbool(bool) : [int]bool; - -function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; -function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool -{ - MapConstBool(false)[x := true] -} - -function {:inline} {:linear "1"} SetCollector1(x: [int]bool) : [int]bool -{ - x -} - -function {:inline} {:linear "2"} SetCollector2(x: [int]bool) : [int]bool -{ - x -} - -var {:layer 0,1} g: int; -var {:layer 0,1} h: int; - -procedure {:yields} {:layer 0,1} SetG(val:int); -ensures {:atomic} |{A: g := val; return true; }|; - -procedure {:yields} {:layer 0,1} SetH(val:int); -ensures {:atomic} |{A: h := val; return true; }|; - -procedure {:yields} {:layer 1} Yield({:linear "1"} x: [int]bool) -requires {:layer 1} x == mapconstbool(true) && g == 0; -ensures {:layer 1} x == mapconstbool(true) && g == 0; -{ - yield; - assert {:layer 1} x == mapconstbool(true) && g == 0; -} - -procedure {:yields} {:layer 1} Allocate() returns ({:linear "tid"} xl: int) -ensures {:layer 1} xl != 0; -{ - yield; - call xl := AllocateLow(); - yield; -} - -procedure {:yields} {:layer 0,1} AllocateLow() returns ({:linear "tid"} xls: int); -ensures {:atomic} |{ A: assume xls != 0; return true; }|; - -procedure {:yields} {:layer 1} A({:linear_in "tid"} tid_in: int, {:linear_in "1"} x: [int]bool, {:linear_in "2"} y: [int]bool) returns ({:linear "tid"} tid_out: int) -requires {:layer 1} x == mapconstbool(true); -requires {:layer 1} y == mapconstbool(true); -{ - var {:linear "tid"} tid_child: int; - tid_out := tid_in; - - yield; - call SetG(0); - - par tid_child := Allocate() | Yield(x); - - async call B(tid_child, x); - - yield; - assert {:layer 1} x == mapconstbool(true); - assert {:layer 1} g == 0; - - call SetH(0); - - yield; - assert {:layer 1} h == 0 && y == mapconstbool(true); - - yield; - call tid_child := Allocate(); - async call C(tid_child, y); - - yield; -} - -procedure {:yields} {:layer 1} B({:linear_in "tid"} tid_in: int, {:linear_in "1"} x_in: [int]bool) -requires {:layer 1} x_in != mapconstbool(false); -{ - var {:linear "tid"} tid_out: int; - var {:linear "1"} x: [int]bool; - tid_out := tid_in; - x := x_in; - - yield; - call SetG(1); - yield; -} - -procedure {:yields} {:layer 1} C({:linear_in "tid"} tid_in: int, {:linear_in "2"} y_in: [int]bool) -requires {:layer 1} y_in != mapconstbool(false); -{ - var {:linear "tid"} tid_out: int; - var {:linear "2"} y: [int]bool; - tid_out := tid_in; - y := y_in; - - yield; - call SetH(1); - yield; -} diff --git a/Test/og/t1.bpl.expect b/Test/og/t1.bpl.expect deleted file mode 100644 index 0b0c936e..00000000 --- a/Test/og/t1.bpl.expect +++ /dev/null @@ -1,9 +0,0 @@ -t1.bpl(65,5): Error: Non-interference check failed -Execution trace: - t1.bpl(84,13): anon0 - (0,0): anon05 - (0,0): inline$SetG_1$0$Entry - t1.bpl(25,21): inline$SetG_1$0$this_A - (0,0): inline$Impl_YieldChecker_A_1$0$L1 - -Boogie program verifier finished with 4 verified, 1 error diff --git a/Test/og/termination.bpl b/Test/og/termination.bpl deleted file mode 100644 index 2d5542dd..00000000 --- a/Test/og/termination.bpl +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -procedure {:yields} {:layer 0} X(); -ensures {:atomic} |{ A: return true; }|; - -procedure {:yields} {:layer 0} Y(); -ensures {:left} |{ A: return true; }|; - -procedure {:yields} {:layer 1} main() { - yield; - call X(); - while (*) - { - call Y(); - } - yield; - assert {:layer 1} true; -} diff --git a/Test/og/termination.bpl.expect b/Test/og/termination.bpl.expect deleted file mode 100644 index d216a01d..00000000 --- a/Test/og/termination.bpl.expect +++ /dev/null @@ -1,3 +0,0 @@ -termination.bpl(9,31): Error: Implementation main fails simulation check C at layer 1. Transactions must be separated by a yield. - -1 type checking errors detected in termination.bpl diff --git a/Test/og/termination2.bpl b/Test/og/termination2.bpl deleted file mode 100644 index 840c27c1..00000000 --- a/Test/og/termination2.bpl +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -procedure {:yields} {:layer 0} X(); -ensures {:atomic} |{ A: return true; }|; - -procedure {:yields} {:layer 0} Y(); -ensures {:left} |{ A: return true; }|; - -procedure {:yields} {:layer 1} main() { - yield; - call X(); - while (*) - invariant {:terminates} {:layer 1} true; - { - call Y(); - } - yield; - assert {:layer 1} true; -} diff --git a/Test/og/termination2.bpl.expect b/Test/og/termination2.bpl.expect deleted file mode 100644 index 6abb715b..00000000 --- a/Test/og/termination2.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 1 verified, 0 errors diff --git a/Test/og/ticket.bpl b/Test/og/ticket.bpl deleted file mode 100644 index 91863e1a..00000000 --- a/Test/og/ticket.bpl +++ /dev/null @@ -1,147 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -function RightOpen(n: int) : [int]bool; -function RightClosed(n: int) : [int]bool; -axiom (forall x: int, y: int :: RightOpen(x)[y] <==> y < x); -axiom (forall x: int, y: int :: RightClosed(x)[y] <==> y <= x); - -type X; -function {:builtin "MapConst"} mapconstbool(bool): [X]bool; -const nil: X; -var {:layer 0,2} t: int; -var {:layer 0,2} s: int; -var {:layer 0,2} cs: X; -var {:layer 0,2} T: [int]bool; - -function {:builtin "MapConst"} MapConstBool(bool) : [X]bool; -function {:inline} {:linear "tid"} TidCollector(x: X) : [X]bool -{ - MapConstBool(false)[x := true] -} -function {:inline} {:linear "tid"} TidSetCollector(x: [X]bool) : [X]bool -{ - x -} - -function {:inline} Inv1(tickets: [int]bool, ticket: int): (bool) -{ - tickets == RightOpen(ticket) -} - -function {:inline} Inv2(tickets: [int]bool, ticket: int, lock: X): (bool) -{ - if (lock == nil) then tickets == RightOpen(ticket) else tickets == RightClosed(ticket) -} - -procedure {:yields} {:layer 2} Allocate({:linear_in "tid"} xls':[X]bool) returns ({:linear "tid"} xls: [X]bool, {:linear "tid"} xl: X) -ensures {:layer 1} {:layer 2} xl != nil; -{ - yield; - call xls, xl := AllocateLow(xls'); - yield; -} - -procedure {:yields} {:layer 2} main({:linear_in "tid"} xls':[X]bool) -requires {:layer 2} xls' == mapconstbool(true); -{ - var {:linear "tid"} tid: X; - var {:linear "tid"} xls: [X]bool; - - yield; - - call Init(xls'); - xls := xls'; - - par Yield1() | Yield2(); - - while (*) - invariant {:layer 1} Inv1(T, t); - invariant {:layer 2} Inv2(T, s, cs); - { - par xls, tid := Allocate(xls) | Yield1() | Yield2(); - async call Customer(tid); - par Yield1() | Yield2(); - } - par Yield1() | Yield2(); -} - -procedure {:yields} {:layer 2} Customer({:linear_in "tid"} tid: X) -requires {:layer 1} Inv1(T, t); -requires {:layer 2} tid != nil && Inv2(T, s, cs); -{ - par Yield1() | Yield2(); - while (*) - invariant {:layer 1} Inv1(T, t); - invariant {:layer 2} Inv2(T, s, cs); - { - call Enter(tid); - par Yield1() | Yield2() | YieldSpec(tid); - call Leave(tid); - par Yield1() | Yield2(); - } - par Yield1() | Yield2(); -} - -procedure {:yields} {:layer 2} Enter({:linear "tid"} tid: X) -requires {:layer 1} Inv1(T, t); -ensures {:layer 1} Inv1(T,t); -requires {:layer 2} tid != nil && Inv2(T, s, cs); -ensures {:layer 2} Inv2(T, s, cs) && cs == tid; -{ - var m: int; - - par Yield1() | Yield2(); - call m := GetTicketAbstract(tid); - par Yield1(); - call WaitAndEnter(tid, m); - par Yield1() | Yield2() | YieldSpec(tid); -} - -procedure {:yields} {:layer 1,2} GetTicketAbstract({:linear "tid"} tid: X) returns (m: int) -requires {:layer 1} Inv1(T, t); -ensures {:layer 1} Inv1(T, t); -ensures {:right} |{ A: havoc m, t; assume !T[m]; T[m] := true; return true; }|; -{ - par Yield1(); - call m := GetTicket(tid); - par Yield1(); -} - -procedure {:yields} {:layer 2} YieldSpec({:linear "tid"} tid: X) -requires {:layer 2} tid != nil && cs == tid; -ensures {:layer 2} cs == tid; -{ - yield; - assert {:layer 2} tid != nil && cs == tid; -} - -procedure {:yields} {:layer 2} Yield2() -requires {:layer 2} Inv2(T, s, cs); -ensures {:layer 2} Inv2(T, s, cs); -{ - yield; - assert {:layer 2} Inv2(T, s, cs); -} - -procedure {:yields} {:layer 1} Yield1() -requires {:layer 1} Inv1(T, t); -ensures {:layer 1} Inv1(T,t); -{ - yield; - assert {:layer 1} Inv1(T,t); -} - -procedure {:yields} {:layer 0,2} Init({:linear "tid"} xls:[X]bool); -ensures {:atomic} |{ A: assert xls == mapconstbool(true); cs := nil; t := 0; s := 0; T := RightOpen(0); return true; }|; - -procedure {:yields} {:layer 0,1} GetTicket({:linear "tid"} tid: X) returns (m: int); -ensures {:atomic} |{ A: m := t; t := t + 1; T[m] := true; return true; }|; - -procedure {:yields} {:layer 0,2} WaitAndEnter({:linear "tid"} tid: X, m:int); -ensures {:atomic} |{ A: assume m <= s; cs := tid; return true; }|; - -procedure {:yields} {:layer 0,2} Leave({:linear "tid"} tid: X); -ensures {:atomic} |{ A: s := s + 1; cs := nil; return true; }|; - -procedure {:yields} {:layer 0,2} AllocateLow({:linear_in "tid"} xls':[X]bool) returns ({:linear "tid"} xls: [X]bool, {:linear "tid"} xl: X); -ensures {:atomic} |{ A: assume xl != nil; return true; }|; diff --git a/Test/og/ticket.bpl.expect b/Test/og/ticket.bpl.expect deleted file mode 100644 index 28c26eab..00000000 --- a/Test/og/ticket.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 16 verified, 0 errors diff --git a/Test/og/treiber-stack.bpl b/Test/og/treiber-stack.bpl deleted file mode 100644 index e1c509ab..00000000 --- a/Test/og/treiber-stack.bpl +++ /dev/null @@ -1,202 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type Node = int; -const unique null: Node; -type lmap; -function {:linear "Node"} dom(lmap): [Node]bool; -function map(lmap): [Node]Node; -function {:builtin "MapConst"} MapConstBool(bool) : [Node]bool; - -function EmptyLmap(): (lmap); -axiom (dom(EmptyLmap()) == MapConstBool(false)); - -function Add(x: lmap, i: Node, v: Node): (lmap); -axiom (forall x: lmap, i: Node, v: Node :: dom(Add(x, i, v)) == dom(x)[i:=true] && map(Add(x, i, v)) == map(x)[i := v]); - -function Remove(x: lmap, i: Node): (lmap); -axiom (forall x: lmap, i: Node :: dom(Remove(x, i)) == dom(x)[i:=false] && map(Remove(x, i)) == map(x)); - -procedure {:yields} {:layer 0,1} ReadTopOfStack() returns (v:Node); -ensures {:right} |{ A: assume dom(Stack)[v] || dom(Used)[v]; return true; }|; - -procedure {:yields} {:layer 0,1} Load(i:Node) returns (v:Node); -ensures {:right} |{ A: assert dom(Stack)[i] || dom(Used)[i]; goto B,C; - B: assume dom(Stack)[i]; v := map(Stack)[i]; return true; - C: assume !dom(Stack)[i]; return true; }|; - -procedure {:yields} {:layer 0,1} Store({:linear_in "Node"} l_in:lmap, i:Node, v:Node) returns ({:linear "Node"} l_out:lmap); -ensures {:both} |{ A: assert dom(l_in)[i]; l_out := Add(l_in, i, v); return true; }|; - -procedure {:yields} {:layer 0,1} TransferToStack(oldVal: Node, newVal: Node, {:linear_in "Node"} l_in:lmap) returns (r: bool, {:linear "Node"} l_out:lmap); -ensures {:atomic} |{ A: assert dom(l_in)[newVal]; - goto B,C; - B: assume oldVal == TopOfStack; TopOfStack := newVal; l_out := EmptyLmap(); Stack := Add(Stack, newVal, map(l_in)[newVal]); r := true; return true; - C: assume oldVal != TopOfStack; l_out := l_in; r := false; return true; }|; - -procedure {:yields} {:layer 0,1} TransferFromStack(oldVal: Node, newVal: Node) returns (r: bool); -ensures {:atomic} |{ A: goto B,C; - B: assume oldVal == TopOfStack; TopOfStack := newVal; Used := Add(Used, oldVal, map(Stack)[oldVal]); Stack := Remove(Stack, oldVal); r := true; return true; - C: assume oldVal != TopOfStack; r := false; return true; }|; - -var {:layer 0} TopOfStack: Node; -var {:linear "Node"} {:layer 0} Stack: lmap; - - -function {:inline} Inv(TopOfStack: Node, Stack: lmap) : (bool) -{ - BetweenSet(map(Stack), TopOfStack, null)[TopOfStack] && - Subset(BetweenSet(map(Stack), TopOfStack, null), Union(Singleton(null), dom(Stack))) -} - -var {:linear "Node"} {:layer 0} Used: lmap; - -procedure {:yields} {:layer 1} push(x: Node, {:linear_in "Node"} x_lmap: lmap) -requires {:layer 1} dom(x_lmap)[x]; -requires {:layer 1} Inv(TopOfStack, Stack); -ensures {:layer 1} Inv(TopOfStack, Stack); -ensures {:atomic} |{ A: Stack := Add(Stack, x, TopOfStack); TopOfStack := x; return true; }|; -{ - var t: Node; - var g: bool; - var {:linear "Node"} t_lmap: lmap; - - yield; - assert {:layer 1} Inv(TopOfStack, Stack); - t_lmap := x_lmap; - while (true) - invariant {:layer 1} dom(t_lmap) == dom(x_lmap); - invariant {:layer 1} Inv(TopOfStack, Stack); - { - call t := ReadTopOfStack(); - call t_lmap := Store(t_lmap, x, t); - call g, t_lmap := TransferToStack(t, x, t_lmap); - if (g) { - assert {:layer 1} map(Stack)[x] == t; - break; - } - yield; - assert {:layer 1} dom(t_lmap) == dom(x_lmap); - assert {:layer 1} Inv(TopOfStack, Stack); - } - yield; - assert {:expand} {:layer 1} Inv(TopOfStack, Stack); -} - -procedure {:yields} {:layer 1} pop() -requires {:layer 1} Inv(TopOfStack, Stack); -ensures {:layer 1} Inv(TopOfStack, Stack); -ensures {:atomic} |{ var t: Node; - A: assume TopOfStack != null; t := TopOfStack; Used := Add(Used, t, map(Stack)[t]); TopOfStack := map(Stack)[t]; Stack := Remove(Stack, t); return true; }|; -{ - var g: bool; - var x: Node; - var t: Node; - - yield; - assert {:layer 1} Inv(TopOfStack, Stack); - while (true) - invariant {:layer 1} Inv(TopOfStack, Stack); - { - call t := ReadTopOfStack(); - if (t != null) { - call x := Load(t); - call g := TransferFromStack(t, x); - if (g) { - break; - } - } - yield; - assert {:layer 1} Inv(TopOfStack, Stack); - } - yield; - assert {:layer 1} Inv(TopOfStack, Stack); -} - -function Equal([int]bool, [int]bool) returns (bool); -function Subset([int]bool, [int]bool) returns (bool); - -function Empty() returns ([int]bool); -function Singleton(int) returns ([int]bool); -function Reachable([int,int]bool, int) returns ([int]bool); -function Union([int]bool, [int]bool) returns ([int]bool); - -axiom(forall x:int :: !Empty()[x]); - -axiom(forall x:int, y:int :: {Singleton(y)[x]} Singleton(y)[x] <==> x == y); -axiom(forall y:int :: {Singleton(y)} Singleton(y)[y]); - -axiom(forall x:int, S:[int]bool, T:[int]bool :: {Union(S,T)[x]}{Union(S,T),S[x]}{Union(S,T),T[x]} Union(S,T)[x] <==> S[x] || T[x]); - -axiom(forall S:[int]bool, T:[int]bool :: {Equal(S,T)} Equal(S,T) <==> Subset(S,T) && Subset(T,S)); -axiom(forall x:int, S:[int]bool, T:[int]bool :: {S[x],Subset(S,T)}{T[x],Subset(S,T)} S[x] && Subset(S,T) ==> T[x]); -axiom(forall S:[int]bool, T:[int]bool :: {Subset(S,T)} Subset(S,T) || (exists x:int :: S[x] && !T[x])); - -//////////////////// -// Between predicate -//////////////////// -function Between(f: [int]int, x: int, y: int, z: int) returns (bool); -function Avoiding(f: [int]int, x: int, y: int, z: int) returns (bool); - - -////////////////////////// -// Between set constructor -////////////////////////// -function BetweenSet(f: [int]int, x: int, z: int) returns ([int]bool); - -//////////////////////////////////////////////////// -// axioms relating Between and BetweenSet -//////////////////////////////////////////////////// -axiom(forall f: [int]int, x: int, y: int, z: int :: {BetweenSet(f, x, z)[y]} BetweenSet(f, x, z)[y] <==> Between(f, x, y, z)); -axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, z), BetweenSet(f, x, z)} Between(f, x, y, z) ==> BetweenSet(f, x, z)[y]); -axiom(forall f: [int]int, x: int, z: int :: {BetweenSet(f, x, z)} Between(f, x, x, x)); -axiom(forall f: [int]int, x: int, z: int :: {BetweenSet(f, x, z)} Between(f, z, z, z)); - - -////////////////////////// -// Axioms for Between -////////////////////////// - -// reflexive -axiom(forall f: [int]int, x: int :: Between(f, x, x, x)); - -// step -axiom(forall f: [int]int, x: int, y: int, z: int, w:int :: {Between(f, y, z, w), f[x]} Between(f, x, f[x], f[x])); - -// reach -axiom(forall f: [int]int, x: int, y: int :: {f[x], Between(f, x, y, y)} Between(f, x, y, y) ==> x == y || Between(f, x, f[x], y)); - -// cycle -axiom(forall f: [int]int, x: int, y:int :: {f[x], Between(f, x, y, y)} f[x] == x && Between(f, x, y, y) ==> x == y); - -// sandwich -axiom(forall f: [int]int, x: int, y: int :: {Between(f, x, y, x)} Between(f, x, y, x) ==> x == y); - -// order1 -axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, y), Between(f, x, z, z)} Between(f, x, y, y) && Between(f, x, z, z) ==> Between(f, x, y, z) || Between(f, x, z, y)); - -// order2 -axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, z)} Between(f, x, y, z) ==> Between(f, x, y, y) && Between(f, y, z, z)); - -// transitive1 -axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, y), Between(f, y, z, z)} Between(f, x, y, y) && Between(f, y, z, z) ==> Between(f, x, z, z)); - -// transitive2 -axiom(forall f: [int]int, x: int, y: int, z: int, w: int :: {Between(f, x, y, z), Between(f, y, w, z)} Between(f, x, y, z) && Between(f, y, w, z) ==> Between(f, x, y, w) && Between(f, x, w, z)); - -// transitive3 -axiom(forall f: [int]int, x: int, y: int, z: int, w: int :: {Between(f, x, y, z), Between(f, x, w, y)} Between(f, x, y, z) && Between(f, x, w, y) ==> Between(f, x, w, z) && Between(f, w, y, z)); - -// This axiom is required to deal with the incompleteness of the trigger for the reflexive axiom. -// It cannot be proved using the rest of the axioms. -axiom(forall f: [int]int, u:int, x: int :: {Between(f, u, x, x)} Between(f, u, x, x) ==> Between(f, u, u, x)); - -// relation between Avoiding and Between -axiom(forall f: [int]int, x: int, y: int, z: int :: {Avoiding(f, x, y, z)} Avoiding(f, x, y, z) <==> (Between(f, x, y, z) || (Between(f, x, y, y) && !Between(f, x, z, z)))); -axiom(forall f: [int]int, x: int, y: int, z: int :: {Between(f, x, y, z)} Between(f, x, y, z) <==> (Avoiding(f, x, y, z) && Avoiding(f, x, z, z))); - -// update -axiom(forall f: [int]int, u: int, v: int, x: int, p: int, q: int :: {Avoiding(f[p := q], u, v, x)} Avoiding(f[p := q], u, v, x) <==> ((Avoiding(f, u, v, p) && Avoiding(f, u, v, x)) || (Avoiding(f, u, p, x) && p != x && Avoiding(f, q, v, p) && Avoiding(f, q, v, x)))); - -axiom (forall f: [int]int, p: int, q: int, u: int, w: int :: {BetweenSet(f[p := q], u, w)} Avoiding(f, u, w, p) ==> Equal(BetweenSet(f[p := q], u, w), BetweenSet(f, u, w))); -axiom (forall f: [int]int, p: int, q: int, u: int, w: int :: {BetweenSet(f[p := q], u, w)} p != w && Avoiding(f, u, p, w) && Avoiding(f, q, w, p) ==> Equal(BetweenSet(f[p := q], u, w), Union(BetweenSet(f, u, p), BetweenSet(f, q, w)))); -axiom (forall f: [int]int, p: int, q: int, u: int, w: int :: {BetweenSet(f[p := q], u, w)} Avoiding(f, u, w, p) || (p != w && Avoiding(f, u, p, w) && Avoiding(f, q, w, p)) || Equal(BetweenSet(f[p := q], u, w), Empty())); \ No newline at end of file diff --git a/Test/og/treiber-stack.bpl.expect b/Test/og/treiber-stack.bpl.expect deleted file mode 100644 index be6b95ba..00000000 --- a/Test/og/treiber-stack.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 6 verified, 0 errors diff --git a/Test/og/wsq.bpl b/Test/og/wsq.bpl deleted file mode 100644 index f4964258..00000000 --- a/Test/og/wsq.bpl +++ /dev/null @@ -1,560 +0,0 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type Tid; -const nil: Tid; - -function {:builtin "MapConst"} MapConstBool(bool) : [Tid]bool; -function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool -{ - MapConstBool(false)[x := true] -} - - - -var {:layer 0,3} H: int; -var {:layer 0,3} T: int; -var {:layer 0,3} items: [int]int; -var {:layer 0} status: [int]bool; -var {:layer 0,3} take_in_cs: bool; -var {:layer 0,3} put_in_cs: bool; -var {:layer 0,3} steal_in_cs: [Tid]bool; -var {:layer 0,3} h_ss: [Tid]int; -var {:layer 0,3} t_ss: [Tid]int; - -const IN_Q: bool; -const NOT_IN_Q: bool; -axiom IN_Q == true; -axiom NOT_IN_Q == false; - -const unique EMPTY: int; -const unique NIL: Tid; -const unique ptTid: Tid; -axiom ptTid != NIL; - -function {:inline} stealerTid(tid: Tid):(bool) { tid != NIL && tid != ptTid } - -function {:inline} ideasInv(put_in_cs:bool, - items:[int]int, - status: [int]bool, - H:int, T:int, - take_in_cs:bool, - steal_in_cs:[Tid]bool, - h_ss:[Tid]int, - t_ss:[Tid]int - ):(bool) -{ - ( - ( (take_in_cs) && h_ss[ptTid] < t_ss[ptTid] ==> (t_ss[ptTid] == T && H <= T && - items[T] != EMPTY && status[T] == IN_Q) ) && - (put_in_cs ==> !take_in_cs) && (take_in_cs ==> !put_in_cs) && - (( (take_in_cs) && H != h_ss[ptTid]) ==> H > h_ss[ptTid]) && - (forall td:Tid :: (stealerTid(td) && steal_in_cs[td] && H == h_ss[td] && H < t_ss[td]) ==> (items[H] != EMPTY && status[H] == IN_Q)) && - (forall td:Tid :: (stealerTid(td) && steal_in_cs[td] && H != h_ss[td]) ==> H > h_ss[td]) - ) -} - -function {:inline} queueInv(steal_in_cs:[Tid]bool, - put_in_cs:bool, - take_in_cs:bool, - items:[int]int, status: [int]bool, _H:int, _T:int):(bool) -{ - ( (forall i:int :: (_H <= i && i <= _T) ==> (status[i] == IN_Q && items[i] != EMPTY)) ) -} - -function {:inline} emptyInv(put_in_cs:bool, take_in_cs:bool, items:[int]int, status:[int]bool, T:int):(bool) -{ - (forall i:int :: (i>=T && !put_in_cs && !take_in_cs) ==> status[i] == NOT_IN_Q && items[i] == EMPTY) -} - -function {:inline} putInv(items:[int]int, status: [int]bool, H:int, T:int):(bool) -{ - (forall i:int :: (H <= i && i < T) ==> (status[i] == IN_Q && items[i] != EMPTY)) -} - -function {:inline} takeInv(items:[int]int, status: [int]bool, H:int, T:int, t:int, h:int):(bool) -{ - (forall i:int :: (h <= i && i <= t) ==> (status[i] == IN_Q && - items[i] != EMPTY) && - t == T - ) -} - -procedure {:yields} {:layer 3} put({:linear "tid"} tid:Tid, task: int) -requires {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && task != EMPTY && !take_in_cs && !put_in_cs; -requires {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); -requires {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); -ensures {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; -ensures {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); -ensures {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); -ensures {:atomic} |{ var i: int; A: assume status[i] == NOT_IN_Q; status[i] := IN_Q; return true; }|; -{ - var t: int; - var {:ghost} oldH:int; - var {:ghost} oldT:int; - var {:ghost} oldStatusT:bool; - - - oldH := H; - oldT := T; - yield; - assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; - assert {:layer 3} {:expand} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H && oldT == T; - assert {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); - - call t := readT_put(tid); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && put_in_cs; - assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} tid == ptTid && t == T; - assert {:layer 3} oldH <= H && oldT == T; - assert {:layer 3} (forall i:int :: i>=T ==> status[i] == NOT_IN_Q && items[i] == EMPTY); - - call writeItems_put(tid,t, task); - - oldH := H; - oldT := T; - oldStatusT := status[T]; - yield; - assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && t == T && tid == ptTid && !take_in_cs && put_in_cs; - assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} items[t] == task; - assert {:layer 3} oldH <= H && oldT == T; - assert {:layer 3} (forall i:int :: i>T ==> status[i] == NOT_IN_Q && items[i] == EMPTY); - - - call writeT_put(tid, t+1); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; - assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} T == t + 1; - assert {:layer 3} oldH <= H && oldT == T; - assert {:layer 3} {:expand} emptyInv(put_in_cs, take_in_cs, items,status,T); -} - -procedure {:yields} {:layer 3} take({:linear "tid"} tid:Tid) returns (task: int, taskstatus: bool) -requires {:layer 3} {:expand} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; -requires {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); -ensures {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs && (task != EMPTY ==> taskstatus == IN_Q); -ensures {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); -ensures {:atomic} |{ var i: int; A: goto B,C; B: assume status[i] == IN_Q; status[i] := NOT_IN_Q; return true; C: return true;}|; -{ - var h, t: int; - var chk: bool; - var {:ghost} oldH:int; - var {:ghost} oldT:int; - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H && oldT == T; - - LOOP_ENTRY_1: - - while(true) - invariant {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; - invariant {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - { - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H && oldT == T; - - call t := readT_take_init(tid); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && !put_in_cs; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} t == T; - assert {:layer 3} items[t-1] == EMPTY ==> H > t-1; - assert {:layer 3} oldH <= H && oldT == T; - - t := t-1; - call writeT_take(tid, t); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && !take_in_cs && !put_in_cs && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} t == T; - assert {:layer 3} items[t] == EMPTY ==> H > t; - assert {:layer 3} oldH <= H && oldT == T; - - call h := readH_take(tid); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && take_in_cs && !put_in_cs && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} t == T; - assert {:layer 3} h <= H; - assert {:layer 3} items[t] == EMPTY ==> H > t; - assert {:layer 3} oldH <= H; - assert {:layer 3} oldT == T; - assert {:layer 3} h <= H; - assert {:layer 3} oldH == h; - - if(t= h; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && take_in_cs && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} t == T && task == items[T]; - assert {:layer 3} T > H ==> items[T] != EMPTY; - assert {:layer 3} oldH <= H && oldT == T && !put_in_cs && take_in_cs; - - if(t>h) { - call takeExitCS(tid); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && !take_in_cs && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} t == T && task == items[t] && task != EMPTY && taskstatus == IN_Q; - assert {:layer 3} oldH <= H && oldT == T && !put_in_cs && !take_in_cs; - return; - } - call writeT_take_eq(tid, h+1); - oldH := H; - oldT := T; - - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} T == h + 1; - assert {:layer 3} oldH <= H; - assert {:layer 3} oldT == T; - assert {:layer 3} task == items[t]; - assert {:layer 3} !put_in_cs; - - call chk := CAS_H_take(tid, h,h+1); - - - oldH := H; - oldT := T; - yield; - assert {:layer 3} chk ==> (h+1 == oldH && h_ss[tid] == oldH -1 && task != EMPTY); - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} h+1 == T; - assert {:layer 3} task == items[t]; - assert {:layer 3} !take_in_cs; - assert {:layer 3} !put_in_cs; - assert {:layer 3} oldH <= H && oldT == T; - - if(!chk) { - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} h+1 == T && task == items[t] && !take_in_cs && !put_in_cs; - assert {:layer 3} oldH <= H && oldT == T; - - goto LOOP_ENTRY_1; - } - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && tid == ptTid && h_ss[tid] == h && t_ss[tid] == t; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} h+1 == T && task == items[t] && !take_in_cs && !put_in_cs; - assert {:layer 3} oldH <= H && oldT == T && task != EMPTY && taskstatus == IN_Q; - - return; - } - - oldH := H; - oldT := T; - yield; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T) && tid == ptTid && !put_in_cs; - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H && oldT == T; - -} - - -procedure {:yields}{:layer 3} steal({:linear "tid"} tid:Tid) returns (task: int, taskstatus: bool) -requires {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && stealerTid(tid) && - !steal_in_cs[tid]; -requires {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); -ensures {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1) && - !steal_in_cs[tid] && (task != EMPTY ==> taskstatus == IN_Q); -ensures {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); -ensures {:atomic} |{ var i: int; A: goto B,C; B: assume status[i] == IN_Q; status[i] := NOT_IN_Q; return true; C: return true;}|; -{ - var h, t: int; - var chk: bool; - var {:ghost} oldH:int; - var {:ghost} oldT:int; - - oldH := H; - oldT := T; - yield; - assert {:layer 3} stealerTid(tid); - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H; - assert {:layer 3} !steal_in_cs[tid]; - - LOOP_ENTRY_2: - while(true) - invariant {:layer 3} stealerTid(tid); - invariant {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - invariant {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - invariant {:layer 3} !steal_in_cs[tid]; - { - oldH := H; - oldT := T; - yield; - assert {:layer 3} stealerTid(tid); - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H; - assert {:layer 3} !steal_in_cs[tid]; - - call h := readH_steal(tid); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} H >= h; - assert {:layer 3} !steal_in_cs[tid]; - assert {:layer 3} h_ss[tid] == h; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H; - - call t := readT_steal(tid); - - - oldH := H; - oldT := T; - yield; - assert {:layer 3} steal_in_cs[tid]; - assert {:layer 3} stealerTid(tid) && H >= h && steal_in_cs[tid] && h_ss[tid] == h; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H && t == t_ss[tid]; - assert {:layer 3} (h < t && take_in_cs && (h_ss[ptTid] < t_ss[ptTid]) && h == H) ==> (H < T); - assert {:layer 3} H >= h; - - if( h>= t) { - - task := EMPTY; - call stealExitCS(tid); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} !steal_in_cs[tid]; - assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid] && h_ss[tid] == h; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H; - return; - } - - call task, taskstatus := readItems(tid, h); - - - oldH := H; - oldT := T; - yield; - assert {:layer 3} stealerTid(tid) && steal_in_cs[tid] && h_ss[tid] == h; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H; - assert {:layer 3} oldH == H && H == h && h_ss[tid] == h ==> task != EMPTY; - assert {:layer 3} (take_in_cs && (h_ss[ptTid] < t_ss[ptTid]) && h == H) ==> (H < T); - assert {:layer 3} h == H ==> status[H] == IN_Q; - - call chk := CAS_H_steal(tid, h,h+1); - - oldH := H; - oldT := T; - yield; - assert {:layer 3} h_ss[tid] == h; - assert {:layer 3} chk ==> (h+1 == oldH && h_ss[tid] == h && task != EMPTY && taskstatus == IN_Q); - assert {:layer 3} (take_in_cs && (h_ss[ptTid] < t_ss[ptTid]) && chk) ==> ((oldH-1) < T); - assert {:layer 3} {:expand} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid]; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} oldH <= H; - - if(!chk) { - goto LOOP_ENTRY_2; - } - - oldH := H; - oldT := T; - yield; - assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid]; - assert {:layer 3} queueInv(steal_in_cs,put_in_cs,take_in_cs,items, status, H, T-1); - assert {:layer 3} ideasInv(put_in_cs,items, status, H, T, take_in_cs, steal_in_cs, h_ss, t_ss); - assert {:layer 3} oldH <= H && task != EMPTY; - return; - } - - oldH := H; - oldT := T; - yield; - assert {:layer 3} chk && task != EMPTY; - assert {:layer 3} stealerTid(tid) && !steal_in_cs[tid]; - assert {:layer 3} oldH <= H; -} - -procedure {:yields}{:layer 0,3} readH_take({:linear "tid"} tid:Tid) returns (y: int); -ensures {:atomic} |{A: assert tid == ptTid; - y := H; - take_in_cs := true; - h_ss[tid] := H; - return true;}|; - -procedure {:yields}{:layer 0,3} readH_steal({:linear "tid"} tid:Tid) returns (y: int); -ensures {:atomic} |{A: assert stealerTid(tid); - assert !steal_in_cs[tid]; - y := H; - h_ss[tid] := H; - return true;}|; - -procedure {:yields}{:layer 0,3} readT_take_init({:linear "tid"} tid:Tid) returns (y: int); -ensures {:atomic} |{A: assert tid != NIL; assert tid == ptTid; y := T; return true;}|; - -procedure {:yields}{:layer 0,3} readT_put({:linear "tid"} tid:Tid) returns (y: int); -ensures {:atomic} |{A: assert tid != NIL; - assert tid == ptTid; - put_in_cs := true; - y := T; - return true;}|; - -procedure {:yields}{:layer 0,3} readT_steal({:linear "tid"} tid:Tid) returns (y: int); -ensures {:atomic} |{A: assert tid != NIL; - assert stealerTid(tid); - assert !steal_in_cs[tid]; - y := T; - t_ss[tid] := T; - steal_in_cs[tid] := true; - return true;}|; - -procedure {:yields}{:layer 0,3} readItems({:linear "tid"} tid:Tid, ind: int) returns (y: int, b:bool); -ensures {:atomic} |{A: y := items[ind]; b := status[ind]; return true; }|; - -procedure {:yields}{:layer 0,3} writeT_put({:linear "tid"} tid:Tid, val: int); -ensures {:atomic} |{A: assert tid == ptTid; - T := T+1; - put_in_cs := false; - return true; }|; - -procedure {:yields}{:layer 0,3} writeT_take({:linear "tid"} tid:Tid, val: int); -ensures {:atomic} |{A: assert tid == ptTid; - T := val; - t_ss[tid] := val; - return true; }|; - -procedure {:yields}{:layer 0,3} writeT_take_abort({:linear "tid"} tid:Tid, val: int); -ensures {:atomic} |{A: assert tid == ptTid; - assert take_in_cs; - T := val; - take_in_cs := false; - return true; }|; - -procedure {:yields}{:layer 0,3} writeT_take_eq({:linear "tid"} tid:Tid, val: int); -ensures {:atomic} |{A: assert tid == ptTid; - T := val; - return true; }|; - -procedure {:yields}{:layer 0,3} takeExitCS({:linear "tid"} tid:Tid); -ensures {:atomic} |{A: assert tid == ptTid; - take_in_cs := false; - return true; }|; - -procedure {:yields}{:layer 0,3} stealExitCS({:linear "tid"} tid:Tid); -ensures {:atomic} |{A: assert stealerTid(tid); - assert steal_in_cs[tid]; - steal_in_cs[tid] := false; - return true; }|; - - -procedure {:yields}{:layer 0,3} writeItems({:linear "tid"} tid:Tid, idx: int, val: int); -ensures {:atomic} |{A: assert tid == ptTid; - assert val != EMPTY; - items[idx] := val; - status[idx] := IN_Q; - return true; }|; - - -procedure {:yields}{:layer 0,3} writeItems_put({:linear "tid"} tid:Tid, idx: int, val: int); -ensures {:atomic} |{A: assert tid == ptTid; - assert val != EMPTY; - items[idx] := val; - status[idx] := IN_Q; - return true; }|; - -procedure {:yields}{:layer 0,3} CAS_H_take({:linear "tid"} tid:Tid, prevVal :int, val: int) - returns (result: bool); -ensures {:atomic} |{ A: assert tid == ptTid; - goto B, C; - B: assume H == prevVal; - take_in_cs := false; - status[H] := NOT_IN_Q; - H := H+1; - result := true; - return true; - C: assume H != prevVal; result := false; - take_in_cs := false; - return true; -}|; - -procedure {:yields}{:layer 0,3} CAS_H_steal({:linear "tid"} tid:Tid, prevVal :int, val: int) - returns (result: bool); -ensures {:atomic} |{ A: assert stealerTid(tid); - goto B, C; - B: assume H == prevVal; - status[H] := NOT_IN_Q; - H := H+1; - result := true; - steal_in_cs[tid] := false; - return true; - C: assume H != prevVal; - result := false; - steal_in_cs[tid] := false; - return true; - }|; \ No newline at end of file diff --git a/Test/og/wsq.bpl.expect b/Test/og/wsq.bpl.expect deleted file mode 100644 index 5b2909f1..00000000 --- a/Test/og/wsq.bpl.expect +++ /dev/null @@ -1,2 +0,0 @@ - -Boogie program verifier finished with 3 verified, 0 errors -- cgit v1.2.3 From 9af64efeb4a057f853bb08cfc0fa8cbdc4a166b2 Mon Sep 17 00:00:00 2001 From: Akash Lal Date: Thu, 23 Apr 2015 14:59:36 +0530 Subject: Minor fixes for AbsHoudini --- Source/Houdini/AbstractHoudini.cs | 86 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/Source/Houdini/AbstractHoudini.cs b/Source/Houdini/AbstractHoudini.cs index 210d9f6c..3415ae78 100644 --- a/Source/Houdini/AbstractHoudini.cs +++ b/Source/Houdini/AbstractHoudini.cs @@ -601,19 +601,24 @@ namespace Microsoft.Boogie.Houdini { // Inline functions (new InlineFunctionCalls()).VisitBlockList(impl.Blocks); - ExtractQuantifiedExprs(impl); + StripOutermostForall(impl); + //ExtractQuantifiedExprs(impl); + ExtractBoolExprs(impl); //CommandLineOptions.Clo.PrintInstrumented = true; - //var tt = new TokenTextWriter(Console.Out); - //impl.Emit(tt, 0); - //tt.Close(); + //using (var tt = new TokenTextWriter(Console.Out)) + // impl.Emit(tt, 0); // Intercept the FunctionCalls of the existential functions, and replace them with Boolean constants var existentialFunctionNames = new HashSet(existentialFunctions.Keys); var fv = new ReplaceFunctionCalls(existentialFunctionNames); fv.VisitBlockList(impl.Blocks); + //using (var tt = new TokenTextWriter(Console.Out)) + // impl.Emit(tt, 0); + + impl2functionsAsserted.Add(impl.Name, fv.functionsAsserted); impl2functionsAssumed.Add(impl.Name, fv.functionsAssumed); @@ -684,6 +689,24 @@ namespace Microsoft.Boogie.Houdini { } } + // convert "foo(... e ...) to: + // (p iff e) ==> foo(... p ...) + // where p is a fresh boolean variable, foo is an existential constant + // and e is a Boolean-typed argument of foo + private void ExtractBoolExprs(Implementation impl) + { + var funcs = new HashSet(existentialFunctions.Keys); + foreach (var blk in impl.Blocks) + { + foreach (var acmd in blk.Cmds.OfType()) + { + var ret = ExtractBoolArgs.Extract(acmd.Expr, funcs); + acmd.Expr = ret.Item1; + impl.LocVars.AddRange(ret.Item2); + } + } + } + // convert "assert e1 && forall x: e2" to // assert e1 && e2[x <- x@bound] private void StripOutermostForall(Implementation impl) @@ -967,6 +990,61 @@ namespace Microsoft.Boogie.Houdini { } + // convert "foo(... e ...) to: + // (p iff e) ==> foo(... p ...) + // where p is a fresh boolean variable, foo is an existential constant + // and e is a Boolean-typed argument of foo + class ExtractBoolArgs : StandardVisitor + { + static int freshConstCounter = 0; + HashSet existentialFunctions; + HashSet newConstants; + + private ExtractBoolArgs(HashSet existentialFunctions) + { + this.existentialFunctions = existentialFunctions; + this.newConstants = new HashSet(); + } + + public static Tuple> Extract(Expr expr, HashSet existentialFunctions) + { + var eq = new ExtractBoolArgs(existentialFunctions); + expr = eq.VisitExpr(expr); + return Tuple.Create(expr, eq.newConstants.AsEnumerable()); + } + + public override Expr VisitNAryExpr(NAryExpr node) + { + if (node.Fun is FunctionCall && existentialFunctions.Contains((node.Fun as FunctionCall).FunctionName)) + { + var constants = new Dictionary(); + for (int i = 0; i < node.Args.Count; i++) + { + if (node.Args[i].Type == Type.Bool) + { + var constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, + "boolArg@const" + freshConstCounter, Microsoft.Boogie.Type.Bool), false); + freshConstCounter++; + constants.Add(constant, node.Args[i]); + node.Args[i] = Expr.Ident(constant); + } + } + + newConstants.UnionWith(constants.Keys); + + Expr ret = Expr.True; + foreach (var tup in constants) + { + ret = Expr.And(ret, Expr.Eq(Expr.Ident(tup.Key), tup.Value)); + } + return Expr.Imp(ret, node); + } + + return base.VisitNAryExpr(node); + } + } + + // convert "foo(... forall e ...) to: // (p iff forall e) ==> foo(... p ...) // where p is a fresh boolean variable and foo is an existential constant -- cgit v1.2.3 From bed8d4a027c635a146911a2ce973046f02a8e719 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Sun, 26 Apr 2015 12:57:16 +0100 Subject: Try to fix the emission of invalid SMT-LIBv2 queries when Boogie has a variable that begins with a ``.``. This was't an issue for Z3 which ignores this but CVC4 is stricter and will emit an error --- Source/Provers/SMTLib/SMTLibNamer.cs | 15 ++++++++++----- Test/prover/usedot.bpl | 9 +++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 Test/prover/usedot.bpl diff --git a/Source/Provers/SMTLib/SMTLibNamer.cs b/Source/Provers/SMTLib/SMTLibNamer.cs index 3ef2039b..40007ab9 100644 --- a/Source/Provers/SMTLib/SMTLibNamer.cs +++ b/Source/Provers/SMTLib/SMTLibNamer.cs @@ -98,9 +98,14 @@ namespace Microsoft.Boogie.SMTLib return "|" + s + "|"; } - static string NonKeyword(string s) + static string FilterReserved(string s) { - if (reservedSmtWords.Contains(s) || char.IsDigit(s[0])) + // Note symbols starting with ``.`` and ``@`` are reserved for internal + // solver use in SMT-LIBv2 however if we check for the first character + // being ``@`` then Boogie's tests fail spectacularly because they are + // used for labels so we don't check for it here. It hopefully won't matter + // in practice because ``@`` cannot be legally used in Boogie identifiers. + if (reservedSmtWords.Contains(s) || char.IsDigit(s[0]) || s[0] == '.') s = "q@" + s; // | and \ are illegal even in quoted identifiers @@ -120,17 +125,17 @@ namespace Microsoft.Boogie.SMTLib public static string QuoteId(string s) { - return AddQuotes(NonKeyword(s)); + return AddQuotes(FilterReserved(s)); } public override string GetQuotedLocalName(object thingie, string inherentName) { - return AddQuotes(base.GetLocalName(thingie, NonKeyword(inherentName))); + return AddQuotes(base.GetLocalName(thingie, FilterReserved(inherentName))); } public override string GetQuotedName(object thingie, string inherentName) { - return AddQuotes(base.GetName(thingie, NonKeyword(inherentName))); + return AddQuotes(base.GetName(thingie, FilterReserved(inherentName))); } public SMTLibNamer() diff --git a/Test/prover/usedot.bpl b/Test/prover/usedot.bpl new file mode 100644 index 00000000..5815236e --- /dev/null +++ b/Test/prover/usedot.bpl @@ -0,0 +1,9 @@ +// RUN: %boogie -typeEncoding:m -proverLog:"%t.smt2" "%s" +// RUN: %OutputCheck "%s" --file-to-check="%t.smt2" +procedure foo() { + // . is an illegal starting character in SMT-LIBv2 + // so test that we don't emit it as a symbol name. + // CHECK-L:(declare-fun q@.x () Int) + var .x:int; + assert .x == 0; +} -- cgit v1.2.3 From 3a69fdd7dd02b3bb77da16c6d0e3958f16689ed1 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 28 Apr 2015 16:46:17 +0100 Subject: Try to add build status icon for the Windows build. --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e86eb187..a976b249 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ # Boogie -[![Build Status](https://travis-ci.org/boogie-org/boogie.svg)](https://travis-ci.org/boogie-org/boogie) +## Build Status + +| Linux | Windows | +|-------------------------------|---------------------------------| +| [![linux build status][1]][2] | [![windows_build_status][3]][4] | + +[1]: https://travis-ci.org/boogie-org/boogie.svg +[2]: https://travis-ci.org/boogie-org/boogie +[3]: https://pmbuilds.inf.ethz.ch/buildStatus/icon?job=boogie +[4]: #FIXME + +## About Boogie is an intermediate verification language (IVL), intended as a layer on which to build program verifiers for other languages. Several program verifiers have -- cgit v1.2.3 From 0f5533a8679a6b0e68cc587582dae8ea49701526 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Wed, 29 Apr 2015 10:47:24 +0200 Subject: Add support for 'verified_under' attributes on procedure calls and invariants. --- Source/Core/AbsyCmd.cs | 14 +++++++ Test/test2/CallVerifiedUnder0.bpl | 42 +++++++++++++++++++++ Test/test2/CallVerifiedUnder0.bpl.expect | 14 +++++++ Test/test2/InvariantVerifiedUnder0.bpl | 54 +++++++++++++++++++++++++++ Test/test2/InvariantVerifiedUnder0.bpl.expect | 23 ++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 Test/test2/CallVerifiedUnder0.bpl create mode 100644 Test/test2/CallVerifiedUnder0.bpl.expect create mode 100644 Test/test2/InvariantVerifiedUnder0.bpl create mode 100644 Test/test2/InvariantVerifiedUnder0.bpl.expect diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs index b5581ea6..137e2363 100644 --- a/Source/Core/AbsyCmd.cs +++ b/Source/Core/AbsyCmd.cs @@ -2656,6 +2656,13 @@ namespace Microsoft.Boogie { reqCopy.Condition = Substituter.Apply(s, req.Condition); AssertCmd/*!*/ a = new AssertRequiresCmd(this, reqCopy); Contract.Assert(a != null); + if (Attributes != null) + { + // Inherit attributes of call. + var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); + attrCopy = Substituter.Apply(s, attrCopy); + a.Attributes = attrCopy; + } a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced; newBlockBody.Add(a); } @@ -2676,6 +2683,13 @@ namespace Microsoft.Boogie { Contract.Assert(expr != null); AssertCmd/*!*/ a = new AssertCmd(tok, expr); Contract.Assert(a != null); + if (Attributes != null) + { + // Inherit attributes of call. + var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); + attrCopy = Substituter.Apply(s, attrCopy); + a.Attributes = attrCopy; + } a.ErrorDataEnhanced = AssertCmd.GenerateBoundVarMiningStrategy(expr); newBlockBody.Add(a); } diff --git a/Test/test2/CallVerifiedUnder0.bpl b/Test/test2/CallVerifiedUnder0.bpl new file mode 100644 index 00000000..9ac9dec7 --- /dev/null +++ b/Test/test2/CallVerifiedUnder0.bpl @@ -0,0 +1,42 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +procedure A(P: bool); + requires P; + +procedure Test0() +{ + call {:verified_under false} A(false); // error +} + + +procedure Test1() +{ + call {:verified_under true} A(false); +} + + +procedure Test2(P: bool, A: bool) +{ + call {:verified_under A} A(P); // error +} + + +procedure Test3(P: bool, A: bool) + requires !A ==> P; +{ + call {:verified_under A} A(P); +} + + +procedure Test4(P: bool, A: bool) +{ + call {:verified_under A} {:verified_under true} A(P); // error +} + + +procedure Test5(P: bool, A: bool) + requires !A ==> P; +{ + call {:verified_under A} {:verified_under true} A(P); +} diff --git a/Test/test2/CallVerifiedUnder0.bpl.expect b/Test/test2/CallVerifiedUnder0.bpl.expect new file mode 100644 index 00000000..5d407874 --- /dev/null +++ b/Test/test2/CallVerifiedUnder0.bpl.expect @@ -0,0 +1,14 @@ +CallVerifiedUnder0.bpl(9,5): Error BP5002: A precondition for this call might not hold. +CallVerifiedUnder0.bpl(5,3): Related location: This is the precondition that might not hold. +Execution trace: + CallVerifiedUnder0.bpl(9,5): anon0 +CallVerifiedUnder0.bpl(21,5): Error BP5002: A precondition for this call might not hold. +CallVerifiedUnder0.bpl(5,3): Related location: This is the precondition that might not hold. +Execution trace: + CallVerifiedUnder0.bpl(21,5): anon0 +CallVerifiedUnder0.bpl(34,5): Error BP5002: A precondition for this call might not hold. +CallVerifiedUnder0.bpl(5,3): Related location: This is the precondition that might not hold. +Execution trace: + CallVerifiedUnder0.bpl(34,5): anon0 + +Boogie program verifier finished with 3 verified, 3 errors diff --git a/Test/test2/InvariantVerifiedUnder0.bpl b/Test/test2/InvariantVerifiedUnder0.bpl new file mode 100644 index 00000000..6cade5a5 --- /dev/null +++ b/Test/test2/InvariantVerifiedUnder0.bpl @@ -0,0 +1,54 @@ +// RUN: %boogie -noinfer "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +procedure Test0() +{ + while (*) + invariant {:verified_under false} false; // error + {} +} + + +procedure Test1() +{ + while (*) + invariant {:verified_under true} false; + {} +} + + +procedure Test2(P: bool, Q: bool, A: bool) +{ + while (*) + invariant {:verified_under A} P; // error + invariant {:verified_under A} Q; // error + {} +} + + +procedure Test3(P: bool, Q: bool, A: bool) + requires !A ==> P; +{ + while (*) + invariant {:verified_under A} P; + invariant {:verified_under A} Q; // error + {} +} + +procedure Test4(P: bool, Q: bool, A: bool) +{ + while (*) + invariant {:verified_under A} {:verified_under true} P; // error + invariant {:verified_under A} {:verified_under true} Q; // error + {} +} + + +procedure Test5(P: bool, Q: bool, A: bool) + requires !A ==> Q; +{ + while (*) + invariant {:verified_under A} {:verified_under true} P; // error + invariant {:verified_under A} {:verified_under true} Q; + {} +} diff --git a/Test/test2/InvariantVerifiedUnder0.bpl.expect b/Test/test2/InvariantVerifiedUnder0.bpl.expect new file mode 100644 index 00000000..171a6760 --- /dev/null +++ b/Test/test2/InvariantVerifiedUnder0.bpl.expect @@ -0,0 +1,23 @@ +InvariantVerifiedUnder0.bpl(7,7): Error BP5001: This assertion might not hold. +Execution trace: + InvariantVerifiedUnder0.bpl(6,5): anon0 +InvariantVerifiedUnder0.bpl(23,7): Error BP5004: This loop invariant might not hold on entry. +Execution trace: + InvariantVerifiedUnder0.bpl(22,5): anon0 +InvariantVerifiedUnder0.bpl(24,7): Error BP5004: This loop invariant might not hold on entry. +Execution trace: + InvariantVerifiedUnder0.bpl(22,5): anon0 +InvariantVerifiedUnder0.bpl(34,7): Error BP5004: This loop invariant might not hold on entry. +Execution trace: + InvariantVerifiedUnder0.bpl(32,5): anon0 +InvariantVerifiedUnder0.bpl(41,7): Error BP5004: This loop invariant might not hold on entry. +Execution trace: + InvariantVerifiedUnder0.bpl(40,5): anon0 +InvariantVerifiedUnder0.bpl(42,7): Error BP5004: This loop invariant might not hold on entry. +Execution trace: + InvariantVerifiedUnder0.bpl(40,5): anon0 +InvariantVerifiedUnder0.bpl(51,7): Error BP5004: This loop invariant might not hold on entry. +Execution trace: + InvariantVerifiedUnder0.bpl(50,5): anon0 + +Boogie program verifier finished with 1 verified, 7 errors -- cgit v1.2.3 From facbadfc4dc5e17e85f19f4b25ce4473478b9958 Mon Sep 17 00:00:00 2001 From: akashlal Date: Fri, 1 May 2015 11:21:22 +0530 Subject: AbsHoudini: made disjunct bound a parameter --- Source/Houdini/AbstractHoudini.cs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Source/Houdini/AbstractHoudini.cs b/Source/Houdini/AbstractHoudini.cs index 3415ae78..fcd41656 100644 --- a/Source/Houdini/AbstractHoudini.cs +++ b/Source/Houdini/AbstractHoudini.cs @@ -1378,7 +1378,6 @@ namespace Microsoft.Boogie.Houdini { class Disjunct { - public static int DisjunctBound = 3; HashSet pos; HashSet neg; bool isTrue; @@ -1390,7 +1389,7 @@ namespace Microsoft.Boogie.Houdini { neg = new HashSet(); } - public Disjunct(IEnumerable pos, IEnumerable neg) + public Disjunct(IEnumerable pos, IEnumerable neg, int bound) { this.isTrue = false; this.pos = new HashSet(pos); @@ -1401,7 +1400,7 @@ namespace Microsoft.Boogie.Houdini { this.pos = new HashSet(); this.neg = new HashSet(); } - if (this.pos.Count + this.neg.Count > DisjunctBound) + if (this.pos.Count + this.neg.Count > bound) { // Set to true this.isTrue = true; @@ -1411,14 +1410,14 @@ namespace Microsoft.Boogie.Houdini { } - public Disjunct OR(Disjunct that) + public Disjunct OR(Disjunct that, int bound) { if (isTrue) return this; if (that.isTrue) return that; - return new Disjunct(this.pos.Concat(that.pos), this.neg.Concat(that.neg)); + return new Disjunct(this.pos.Concat(that.pos), this.neg.Concat(that.neg), bound); } public bool Implies(Disjunct that) @@ -1441,17 +1440,19 @@ namespace Microsoft.Boogie.Houdini { // Conjunction of Disjuncts List conjuncts; + int DisjunctBound; bool isFalse; - public PredicateAbsElem() + public PredicateAbsElem(int bound) { this.conjuncts = new List(); this.isFalse = true; + this.DisjunctBound = bound; } public IAbstractDomain Bottom() { - return new PredicateAbsElem(); + return new PredicateAbsElem(DisjunctBound); } public IAbstractDomain MakeTop(out bool changed) @@ -1462,7 +1463,7 @@ namespace Microsoft.Boogie.Houdini { return this; } changed = true; - var ret = new PredicateAbsElem(); + var ret = new PredicateAbsElem(DisjunctBound); ret.isFalse = false; return ret; } @@ -1476,21 +1477,21 @@ namespace Microsoft.Boogie.Houdini { if (!this.isFalse && conjuncts.Count == 0) return this; - var ret = new PredicateAbsElem(); + var ret = new PredicateAbsElem(DisjunctBound); ret.isFalse = false; for (int i = 0; i < state.Count; i++) { var b = (state[i] as Model.Boolean).Value; Disjunct d = null; - if (b) d = new Disjunct(new int[] { i }, new int[] { }); - else d = new Disjunct(new int[] { }, new int[] { i }); + if (b) d = new Disjunct(new int[] { i }, new int[] { }, DisjunctBound); + else d = new Disjunct(new int[] { }, new int[] { i }, DisjunctBound); if (isFalse) ret.AddDisjunct(d); else { - conjuncts.Iter(c => ret.AddDisjunct(c.OR(d))); + conjuncts.Iter(c => ret.AddDisjunct(c.OR(d, DisjunctBound))); } } @@ -2213,7 +2214,8 @@ namespace Microsoft.Boogie.Houdini { System.Tuple.Create("HoudiniConst", HoudiniConst.GetBottom() as IAbstractDomain), System.Tuple.Create("Intervals", new Intervals() as IAbstractDomain), System.Tuple.Create("ConstantProp", ConstantProp.GetBottom() as IAbstractDomain), - System.Tuple.Create("PredicateAbs", new PredicateAbsElem() as IAbstractDomain), + System.Tuple.Create("PredicateAbs", new PredicateAbsElem(3) as IAbstractDomain), + System.Tuple.Create("PredicateAbsFull", new PredicateAbsElem(1000) as IAbstractDomain), System.Tuple.Create("ImplicationDomain", ImplicationDomain.GetBottom() as IAbstractDomain), System.Tuple.Create("PowDomain", PowDomain.GetBottom() as IAbstractDomain), System.Tuple.Create("EqualitiesDomain", EqualitiesDomain.GetBottom() as IAbstractDomain), -- cgit v1.2.3 From 0901edfa9185f2e2bbd331130b391dd1dda06f16 Mon Sep 17 00:00:00 2001 From: akashlal Date: Fri, 1 May 2015 23:21:22 +0530 Subject: Fix for AbsHoudini --- Source/Houdini/AbstractHoudini.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Source/Houdini/AbstractHoudini.cs b/Source/Houdini/AbstractHoudini.cs index fcd41656..522e8174 100644 --- a/Source/Houdini/AbstractHoudini.cs +++ b/Source/Houdini/AbstractHoudini.cs @@ -1355,6 +1355,13 @@ namespace Microsoft.Boogie.Houdini { } } + public class PredicateAbsFullElem : PredicateAbsElem + { + public PredicateAbsFullElem() + : base(1000) + { } + } + public class PredicateAbsElem : IAbstractDomain { public static class ExprExt @@ -1443,6 +1450,13 @@ namespace Microsoft.Boogie.Houdini { int DisjunctBound; bool isFalse; + public PredicateAbsElem() + { + this.conjuncts = new List(); + this.isFalse = true; + this.DisjunctBound = 3; + } + public PredicateAbsElem(int bound) { this.conjuncts = new List(); @@ -2214,8 +2228,8 @@ namespace Microsoft.Boogie.Houdini { System.Tuple.Create("HoudiniConst", HoudiniConst.GetBottom() as IAbstractDomain), System.Tuple.Create("Intervals", new Intervals() as IAbstractDomain), System.Tuple.Create("ConstantProp", ConstantProp.GetBottom() as IAbstractDomain), - System.Tuple.Create("PredicateAbs", new PredicateAbsElem(3) as IAbstractDomain), - System.Tuple.Create("PredicateAbsFull", new PredicateAbsElem(1000) as IAbstractDomain), + System.Tuple.Create("PredicateAbs", new PredicateAbsElem() as IAbstractDomain), + System.Tuple.Create("PredicateAbsFull", new PredicateAbsFullElem() as IAbstractDomain), System.Tuple.Create("ImplicationDomain", ImplicationDomain.GetBottom() as IAbstractDomain), System.Tuple.Create("PowDomain", PowDomain.GetBottom() as IAbstractDomain), System.Tuple.Create("EqualitiesDomain", EqualitiesDomain.GetBottom() as IAbstractDomain), -- cgit v1.2.3 From c09814e1ae44a0bee53abb6e8e65b79c1da03d9e Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Wed, 6 May 2015 17:52:52 +0200 Subject: Make it preserve the fact that the value of an assumption variable never becomes logically weaker after a havoc. --- Source/VCGeneration/ConditionGeneration.cs | 16 ++++++++++-- Test/test2/AssumptionVariables0.bpl | 41 +++++++++++++++++++++++++++--- Test/test2/AssumptionVariables0.bpl.expect | 22 ++++++++-------- 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs index 515ec16d..206e0ee7 100644 --- a/Source/VCGeneration/ConditionGeneration.cs +++ b/Source/VCGeneration/ConditionGeneration.cs @@ -1742,8 +1742,8 @@ namespace VC { Contract.Assert(c != null); // If an assumption variable for postconditions is included here, it must have been assigned within a loop. // We do not need to havoc it if we have performed a modular proof of the loop (i.e., using only the loop - // invariant) in the previous snapshot and are therefore not going refer to the assumption variable after - // the loop. We can achieve this by simply not updating/adding it in the incarnation map. + // invariant) in the previous snapshot and, consequently, the corresponding assumption did not affect the + // anything after the loop. We can achieve this by simply not updating/adding it in the incarnation map. List havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##post##"))).ToList(); // First, compute the new incarnations foreach (IdentifierExpr ie in havocVars) { @@ -1767,6 +1767,18 @@ namespace VC { } } } + + // Add the following assume-statement for each assumption variable 'v', where 'v_post' is the new incarnation and 'v_pre' is the old one: + // assume v_post ==> v_pre; + foreach (IdentifierExpr ie in havocVars) + { + if (QKeyValue.FindBoolAttribute(ie.Decl.Attributes, "assumption")) + { + var preInc = (Expr)(preHavocIncarnationMap[ie.Decl].Clone()); + var postInc = (Expr)(incarnationMap[ie.Decl].Clone()); + passiveCmds.Add(new AssumeCmd(c.tok, Expr.Imp(postInc, preInc))); + } + } } #endregion else if (c is CommentCmd) { diff --git a/Test/test2/AssumptionVariables0.bpl b/Test/test2/AssumptionVariables0.bpl index cc73707c..766c9d1e 100644 --- a/Test/test2/AssumptionVariables0.bpl +++ b/Test/test2/AssumptionVariables0.bpl @@ -28,13 +28,46 @@ procedure Test2() } -var {:assumption} a0: bool; +var {:assumption} ga0: bool; procedure Test3() - modifies a0; + modifies ga0; { - a0 := a0 && true; + ga0 := ga0 && true; - assert a0; // error + assert ga0; // error +} + + +procedure Test4() +{ + var {:assumption} a0: bool; + var tmp: bool; + + tmp := a0; + + havoc a0; + + assert a0 ==> tmp; +} + + +procedure Test5(A: bool) +{ + var {:assumption} a0: bool; + var tmp0, tmp1: bool; + + a0 := a0 && A; + tmp0 := a0; + + havoc a0; + + assert a0 ==> tmp0; + + tmp1 := a0; + + havoc a0; + + assert a0 ==> tmp1; } diff --git a/Test/test2/AssumptionVariables0.bpl.expect b/Test/test2/AssumptionVariables0.bpl.expect index 54ddb2a9..44292082 100644 --- a/Test/test2/AssumptionVariables0.bpl.expect +++ b/Test/test2/AssumptionVariables0.bpl.expect @@ -1,11 +1,11 @@ -AssumptionVariables0.bpl(17,5): Error BP5001: This assertion might not hold. -Execution trace: - AssumptionVariables0.bpl(15,8): anon0 -AssumptionVariables0.bpl(27,5): Error BP5001: This assertion might not hold. -Execution trace: - AssumptionVariables0.bpl(25,5): anon0 -AssumptionVariables0.bpl(39,5): Error BP5001: This assertion might not hold. -Execution trace: - AssumptionVariables0.bpl(37,8): anon0 - -Boogie program verifier finished with 1 verified, 3 errors +AssumptionVariables0.bpl(17,5): Error BP5001: This assertion might not hold. +Execution trace: + AssumptionVariables0.bpl(15,8): anon0 +AssumptionVariables0.bpl(27,5): Error BP5001: This assertion might not hold. +Execution trace: + AssumptionVariables0.bpl(25,5): anon0 +AssumptionVariables0.bpl(39,5): Error BP5001: This assertion might not hold. +Execution trace: + AssumptionVariables0.bpl(37,9): anon0 + +Boogie program verifier finished with 3 verified, 3 errors -- cgit v1.2.3 From 0234f41446ed24b0327497aaedf0caafcc0afb0c Mon Sep 17 00:00:00 2001 From: Akash Lal Date: Thu, 7 May 2015 15:18:11 +0530 Subject: Fix for secureVCGen --- Source/VCGeneration/StratifiedVC.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index 6f8d3668..e88eb55e 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -2609,6 +2609,9 @@ namespace VC { if(impl.LocVars.Any(v => isVisible(v))) throw new InvalidProgramForSecureVc("SecureVc: Visible Local variables not allowed"); + // Desugar procedure calls + DesugarCalls(impl); + // Gather spec, remove existing ensures var secureAsserts = new List(); var logicalAsserts = new List(); -- cgit v1.2.3 From 86b45ab19c90f6759f5685b1616961e1400fa4ba Mon Sep 17 00:00:00 2001 From: Akash Lal Date: Thu, 7 May 2015 15:18:53 +0530 Subject: SecureVC: example --- Test/secure/tworound.bpl | 116 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Test/secure/tworound.bpl diff --git a/Test/secure/tworound.bpl b/Test/secure/tworound.bpl new file mode 100644 index 00000000..a78c4af4 --- /dev/null +++ b/Test/secure/tworound.bpl @@ -0,0 +1,116 @@ +type T = bv4; +function {:bvbuiltin "bvult"} bvlt(p1: T, p2: T) : bool; // unsigned less than +function {:bvbuiltin "bvxor"} xorT(p1: T, p2: T) : T; +function {:bvbuiltin "bvadd"} bvadd(p1: T, p2: T) : T; + + +procedure bar({:visible} v: T) + returns ({:hidden} h: T) + ensures true; +{ + h := v; +} + +procedure foo0({:visible} x1: T, {:visible} x2: T, {:hidden} y1: T, {:hidden} y2: T) + returns ({:visible} r1: bool, {:visible} r2: bool, + {:visible} s1: T, {:visible} s2: T, {:visible} s3: T, {:visible} s4: T) + ensures (r2 == bvlt(bvadd(x1,x2), bvadd(y1,y2))) && (r1 == bvlt(x1, y1)); +{ + var {:hidden} t1, t2: T; + + r1 := bvlt(x1, y1); + + havoc s1; + havoc s2; + + s3 := xorT(x1, s1); + s4 := xorT(y1, s2); + + t1 := xorT(s1, s3); + t2 := xorT(s2, s4); + + r2 := bvlt(bvadd(x2, t1), bvadd(y2, t2)); +} + + +procedure foo1({:visible} x1: T, {:visible} x2: T, {:hidden} y1: T, {:hidden} y2: T) + returns ({:visible} r1: bool, {:visible} r2: bool, + {:visible} s1: T, {:visible} s2: T, {:hidden} s3: T, {:hidden} s4: T) + ensures (r2 == bvlt(bvadd(x1,x2), bvadd(y1,y2))) && (r1 == bvlt(x1, y1)); +{ + var {:hidden} t1, t2: T; + + r1 := bvlt(x1, y1); + + havoc s1; + havoc s2; + + s3 := xorT(x1, s1); + s4 := xorT(y1, s2); + + t1 := xorT(s1, s3); + t2 := xorT(s2, s4); + + r2 := bvlt(bvadd(x2, t1), bvadd(y2, t2)); +} + + + +procedure foo2({:visible} x1: T, {:visible} x2: T, {:hidden} y1: T, {:hidden} y2: T) + returns ({:visible} r1: bool, {:visible} r2: bool, + {:visible} s1: T, {:visible} s2: T) + ensures (r2 == bvlt(bvadd(x1,x2), bvadd(y1,y2))) && (r1 == bvlt(x1, y1)); +{ + var {:hidden} t1, t2: T; + var {:hidden} s3, s4: T; + + r1 := bvlt(x1, y1); + + havoc s1; + havoc s2; + + s3 := xorT(x1, s1); + s4 := xorT(y1, s2); + + t1 := xorT(s1, s3); + t2 := xorT(s2, s4); + + r2 := bvlt(bvadd(x2, t1), bvadd(y2, t2)); +} + +procedure foo3({:visible} x1: T, {:visible} x2: T, {:hidden} y1: T, {:hidden} y2: T) + returns ({:visible} r1: bool, {:visible} r2: bool, + {:visible} s1: T, {:visible} s2: T, {:hidden} s3: T, {:hidden} s4: T) + ensures (r2 == bvlt(bvadd(x1,x2), bvadd(y1,y2))) && (r1 == bvlt(x1, y1)) && (s4 == xorT(y1,s2)) && (s3 == xorT(x1, s1)); +{ + var {:hidden} t1, t2: T; + + r1 := bvlt(x1, y1); + + havoc s1; + havoc s2; + + s3 := xorT(x1, s1); + s4 := xorT(y1, s2); + + t1 := xorT(s1, s3); + t2 := xorT(s2, s4); + + r2 := bvlt(bvadd(x2, t1), bvadd(y2, t2)); +} + + + +procedure bid({:visible} x1: T, {:visible} x2: T, {:hidden} y1: T, {:hidden} y2: T) + returns ({:visible} r: bool) + ensures r == bvlt(bvadd(x1,x2), bvadd(y1,y2)); +{ + var {:hidden} r1, r2: bool; + var {:hidden} s1, s2, s3, s4: T; + + call r1, r2, s1, s2, s3, s4 := foo1(x1, x2, y1, y2); + + r := r2; +} + + -- cgit v1.2.3 From d4d66e2ad626eb1539e2b3e3aa0e88ad6b7746aa Mon Sep 17 00:00:00 2001 From: Akash Lal Date: Wed, 13 May 2015 14:33:48 +0530 Subject: Fix for printFixedPoint when dealing with functions --- Source/Provers/SMTLib/TypeDeclCollector.cs | 1 + Source/VCGeneration/FixedpointVC.cs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Provers/SMTLib/TypeDeclCollector.cs b/Source/Provers/SMTLib/TypeDeclCollector.cs index 30363102..9205d54c 100644 --- a/Source/Provers/SMTLib/TypeDeclCollector.cs +++ b/Source/Provers/SMTLib/TypeDeclCollector.cs @@ -231,6 +231,7 @@ void ObjectInvariant() else decl = "(declare-fun " + printedName + " (" + argTypes + ") " + TypeToStringReg(f.OutParams[0].TypedIdent.Type) + ")"; AddDeclaration(decl); + if (declHandler != null) declHandler.FuncDecl(f); } KnownFunctions.Add(f); } else { diff --git a/Source/VCGeneration/FixedpointVC.cs b/Source/VCGeneration/FixedpointVC.cs index 7dbf6b05..5c698633 100644 --- a/Source/VCGeneration/FixedpointVC.cs +++ b/Source/VCGeneration/FixedpointVC.cs @@ -2189,7 +2189,13 @@ namespace Microsoft.Boogie idx.Add(args[1]); return Expr.Store(args[0],idx,args[2]); } - + + if (f.Op is VCExprBoogieFunctionOp) + { + return new NAryExpr(Token.NoToken, + new FunctionCall((f.Op as VCExprBoogieFunctionOp).Func), args); + } + var op = VCOpToOp (f.Op); return MakeBinary(op,args); } -- cgit v1.2.3 From 6d5ddf853694b2b8014585dd1e40cc10efbaddea Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Sun, 17 May 2015 13:06:58 +0200 Subject: Make caching of verification results more fine-grained for changes that affect preconditions. --- Source/Core/Absy.cs | 24 +++++ Source/Core/AbsyCmd.cs | 33 ++---- Source/Core/AbsyExpr.cs | 23 ++++ Source/Core/DeadVarElim.cs | 2 +- Source/Core/Duplicator.cs | 37 ++++++- Source/ExecutionEngine/VerificationResultCache.cs | 71 +++++++++++- Source/VCGeneration/ConditionGeneration.cs | 13 ++- Test/snapshots/Snapshots34.v0.bpl | 7 ++ Test/snapshots/Snapshots34.v1.bpl | 6 ++ Test/snapshots/Snapshots35.v0.bpl | 7 ++ Test/snapshots/Snapshots35.v1.bpl | 6 ++ Test/snapshots/runtest.snapshot | 2 +- Test/snapshots/runtest.snapshot.expect | 126 +++++++++++++++------- 13 files changed, 285 insertions(+), 72 deletions(-) create mode 100644 Test/snapshots/Snapshots34.v0.bpl create mode 100644 Test/snapshots/Snapshots34.v1.bpl create mode 100644 Test/snapshots/Snapshots35.v0.bpl create mode 100644 Test/snapshots/Snapshots35.v1.bpl diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs index a1a54024..56bfc90f 100644 --- a/Source/Core/Absy.cs +++ b/Source/Core/Absy.cs @@ -2427,6 +2427,28 @@ namespace Microsoft.Boogie { functionDependencies.Add(function); } + public bool SignatureEquals(DeclWithFormals other) + { + Contract.Requires(other != null); + + string sig = null; + string otherSig = null; + using (var strWr = new System.IO.StringWriter()) + using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) + { + EmitSignature(tokTxtWr, this is Function); + sig = strWr.ToString(); + } + + using (var otherStrWr = new System.IO.StringWriter()) + using (var otherTokTxtWr = new TokenTextWriter("", otherStrWr, false, false)) + { + EmitSignature(otherTokTxtWr, other is Function); + otherSig = otherStrWr.ToString(); + } + return sig == otherSig; + } + protected void EmitSignature(TokenTextWriter stream, bool shortRet) { Contract.Requires(stream != null); Type.EmitOptionalTypeParams(stream, TypeParameters); @@ -3295,6 +3317,8 @@ namespace Microsoft.Boogie { RecycledFailingAssertions.Add(assertion); } + public Cmd ExplicitAssumptionAboutCachedPrecondition { get; set; } + // Strongly connected components private StronglyConnectedComponents scc; [ContractInvariantMethod] diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs index 137e2363..eb8b8e1e 100644 --- a/Source/Core/AbsyCmd.cs +++ b/Source/Core/AbsyCmd.cs @@ -1144,6 +1144,12 @@ namespace Microsoft.Boogie { return; } + if (cmd.IrrelevantForChecksumComputation) + { + cmd.Checksum = currentChecksum; + return; + } + var assumeCmd = cmd as AssumeCmd; if (assumeCmd != null && QKeyValue.FindBoolAttribute(assumeCmd.Attributes, "assumption_variable_initialization")) @@ -1161,7 +1167,7 @@ namespace Microsoft.Boogie { if (havocCmd != null) { tokTxtWr.Write("havoc "); - var relevantVars = havocCmd.Vars.Where(e => usedVariables.Contains(e.Decl) && !e.Decl.Name.StartsWith("a##post##")).OrderBy(e => e.Name).ToList(); + var relevantVars = havocCmd.Vars.Where(e => usedVariables.Contains(e.Decl) && !e.Decl.Name.StartsWith("a##cached##")).OrderBy(e => e.Name).ToList(); relevantVars.Emit(tokTxtWr, true); tokTxtWr.WriteLine(";"); } @@ -1244,6 +1250,7 @@ namespace Microsoft.Boogie { public abstract class Cmd : Absy { public byte[] Checksum { get; internal set; } public byte[] SugaredCmdChecksum { get; internal set; } + public bool IrrelevantForChecksumComputation { get; set; } public Cmd(IToken/*!*/ tok) : base(tok) { @@ -2849,7 +2856,7 @@ namespace Microsoft.Boogie { var clauses = procedure.Ensures.Select(e => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, substOldCombined, e.Condition, program)).Concat(modifies); // TODO(wuestholz): Try extracting a function for each clause: // return Conjunction(clauses.Select(c => extract(c))); - var conj = Conjunction(clauses); + var conj = Expr.And(clauses, true); return conj != null ? extract(conj) : conj; } @@ -2860,30 +2867,10 @@ namespace Microsoft.Boogie { var clauses = procedure.Requires.Where(r => !r.Free).Select(r => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, r.Condition, program)); // TODO(wuestholz): Try extracting a function for each clause: // return Conjunction(clauses.Select(c => extract(c))); - var conj = Conjunction(clauses); + var conj = Expr.And(clauses, true); return conj != null ? extract(conj) : conj; } - private static Expr Conjunction(IEnumerable conjuncts) - { - // TODO(wuestholz): Maybe we should use 'LiteralExpr.BinaryTreeAnd' instead. - Expr result = null; - foreach (var c in conjuncts) - { - if (result != null) - { - result = LiteralExpr.And(result, c); - result.Type = Type.Bool; - } - else - { - result = c; - result.Type = Type.Bool; - } - } - return result; - } - public override Absy StdDispatch(StandardVisitor visitor) { //Contract.Requires(visitor != null); Contract.Ensures(Contract.Result() != null); diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index f3a943b8..c19140d7 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -467,6 +467,29 @@ namespace Microsoft.Boogie { var mid = (start + end) / 2; return Expr.And(BinaryTreeAnd(terms, start, mid), BinaryTreeAnd(terms, mid + 1, end)); } + + public static Expr And(IEnumerable conjuncts, bool returnNullIfEmpty = false) + { + Expr result = null; + foreach (var c in conjuncts) + { + if (result != null) + { + result = LiteralExpr.And(result, c); + result.Type = Type.Bool; + } + else + { + result = c; + result.Type = Type.Bool; + } + } + if (result == null && !returnNullIfEmpty) + { + result = Expr.True; + } + return result; + } } [ContractClassFor(typeof(Expr))] public abstract class ExprContracts : Expr { diff --git a/Source/Core/DeadVarElim.cs b/Source/Core/DeadVarElim.cs index 77086f0f..0feb5e35 100644 --- a/Source/Core/DeadVarElim.cs +++ b/Source/Core/DeadVarElim.cs @@ -539,7 +539,7 @@ namespace Microsoft.Boogie { HavocCmd/*!*/ havocCmd = (HavocCmd)cmd; foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { Contract.Assert(expr != null); - if (expr.Decl != null && !(QKeyValue.FindBoolAttribute(expr.Decl.Attributes, "assumption") && expr.Decl.Name.StartsWith("a##post##"))) { + if (expr.Decl != null && !(QKeyValue.FindBoolAttribute(expr.Decl.Attributes, "assumption") && expr.Decl.Name.StartsWith("a##cached##"))) { liveSet.Remove(expr.Decl); } } diff --git a/Source/Core/Duplicator.cs b/Source/Core/Duplicator.cs index 181b80a1..7f021c43 100644 --- a/Source/Core/Duplicator.cs +++ b/Source/Core/Duplicator.cs @@ -583,6 +583,15 @@ namespace Microsoft.Boogie { return (Expr)new FunctionCallReresolvingReplacingOldSubstituter(program, always, forOld).Visit(expr); } + public static Expr FunctionCallReresolvingApply(Substitution always, Substitution forOld, Expr expr, Program program) + { + Contract.Requires(always != null); + Contract.Requires(forOld != null); + Contract.Requires(expr != null); + Contract.Ensures(Contract.Result() != null); + return (Expr)new FunctionCallReresolvingNormalSubstituter(program, always, forOld).Visit(expr); + } + // ----------------------------- Substitutions for Cmd ------------------------------- /// @@ -660,7 +669,7 @@ namespace Microsoft.Boogie { // ------------------------------------------------------------ - private sealed class NormalSubstituter : Duplicator + private class NormalSubstituter : Duplicator { private readonly Substitution/*!*/ always; private readonly Substitution/*!*/ forold; @@ -744,6 +753,32 @@ namespace Microsoft.Boogie { } } + private sealed class FunctionCallReresolvingNormalSubstituter : NormalSubstituter + { + readonly Program Program; + + public FunctionCallReresolvingNormalSubstituter(Program program, Substitution always, Substitution forold) + : base(always, forold) + { + Program = program; + } + + public override Expr VisitNAryExpr(NAryExpr node) + { + var result = base.VisitNAryExpr(node); + var nAryExpr = result as NAryExpr; + if (nAryExpr != null) + { + var funCall = nAryExpr.Fun as FunctionCall; + if (funCall != null) + { + funCall.Func = Program.FindFunction(funCall.FunctionName); + } + } + return result; + } + } + private class ReplacingOldSubstituter : Duplicator { private readonly Substitution/*!*/ always; private readonly Substitution/*!*/ forold; diff --git a/Source/ExecutionEngine/VerificationResultCache.cs b/Source/ExecutionEngine/VerificationResultCache.cs index 5d20e6e8..63e88dfe 100644 --- a/Source/ExecutionEngine/VerificationResultCache.cs +++ b/Source/ExecutionEngine/VerificationResultCache.cs @@ -96,7 +96,64 @@ namespace Microsoft.Boogie assumptionVariableCount = 0; temporaryVariableCount = 0; currentImplementation = implementation; - var result = VisitImplementation(implementation); + + #region Introduce explict assumption about the precondition. + + var oldProc = programInCachedSnapshot.FindProcedure(currentImplementation.Proc.Name); + if (oldProc != null + && oldProc.DependencyChecksum != currentImplementation.Proc.DependencyChecksum + && currentImplementation.ExplicitAssumptionAboutCachedPrecondition == null) + { + var axioms = new List(); + var after = new List(); + Expr assumedExpr = new LiteralExpr(Token.NoToken, false); + var canUseSpecs = DependencyCollector.CanExpressOldSpecs(oldProc, Program, true); + if (canUseSpecs && oldProc.SignatureEquals(currentImplementation.Proc)) + { + var always = Substituter.SubstitutionFromHashtable(currentImplementation.GetImplFormalMap(), true, currentImplementation.Proc); + var forOld = Substituter.SubstitutionFromHashtable(new Dictionary()); + var clauses = oldProc.Requires.Select(r => Substituter.FunctionCallReresolvingApply(always, forOld, r.Condition, Program)); + var conj = Expr.And(clauses, true); + assumedExpr = conj != null ? FunctionExtractor.Extract(conj, Program, axioms) : new LiteralExpr(Token.NoToken, true); + } + + if (assumedExpr != null) + { + var lv = new LocalVariable(Token.NoToken, + new TypedIdent(Token.NoToken, string.Format("a##cached##{0}", FreshAssumptionVariableName), Type.Bool), + new QKeyValue(Token.NoToken, "assumption", new List(), null)); + currentImplementation.InjectAssumptionVariable(lv, !canUseSpecs); + var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, lv)); + var rhs = LiteralExpr.And(new IdentifierExpr(Token.NoToken, lv), assumedExpr); + var assumed = new AssignCmd(currentImplementation.tok, new List { lhs }, new List { rhs }); + currentImplementation.ExplicitAssumptionAboutCachedPrecondition = assumed; + after.Add(assumed); + } + + if (CommandLineOptions.Clo.TraceCachingForTesting || CommandLineOptions.Clo.TraceCachingForBenchmarking) + { + using (var tokTxtWr = new TokenTextWriter("", Console.Out, false, false)) + { + var loc = currentImplementation.tok != null && currentImplementation.tok != Token.NoToken ? string.Format("{0}({1},{2})", currentImplementation.tok.filename, currentImplementation.tok.line, currentImplementation.tok.col) : ""; + Console.Out.WriteLine("Processing implementation {0} (at {1}):", currentImplementation.Name, loc); + foreach (var a in axioms) + { + Console.Out.Write(" >>> added axiom: "); + a.Expr.Emit(tokTxtWr); + Console.Out.WriteLine(); + } + foreach (var b in after) + { + Console.Out.Write(" >>> added after assuming the current precondition: "); + b.Emit(tokTxtWr, 0); + } + } + } + } + + #endregion + + var result = VisitImplementation(currentImplementation); currentImplementation = null; this.programInCachedSnapshot = null; return result; @@ -192,7 +249,7 @@ namespace Microsoft.Boogie Expr assumedExpr = new LiteralExpr(Token.NoToken, false); // TODO(wuestholz): Try out two alternatives: only do this for low priority implementations or not at all. var canUseSpecs = DependencyCollector.CanExpressOldSpecs(oldProc, Program); - if (canUseSpecs) + if (canUseSpecs && oldProc.SignatureEquals(node.Proc)) { var desugaring = node.Desugaring; Contract.Assert(desugaring != null); @@ -231,12 +288,16 @@ namespace Microsoft.Boogie } assumedExpr = node.Postcondition(oldProc, eqs, oldSubst, Program, e => FunctionExtractor.Extract(e, Program, axioms)); + if (assumedExpr == null) + { + assumedExpr = new LiteralExpr(Token.NoToken, true); + } } if (assumedExpr != null) { var lv = new LocalVariable(Token.NoToken, - new TypedIdent(Token.NoToken, string.Format("a##post##{0}", FreshAssumptionVariableName), Type.Bool), + new TypedIdent(Token.NoToken, string.Format("a##cached##{0}", FreshAssumptionVariableName), Type.Bool), new QKeyValue(Token.NoToken, "assumption", new List(), null)); node.AssignedAssumptionVariable = lv; currentImplementation.InjectAssumptionVariable(lv, !canUseSpecs); @@ -431,7 +492,7 @@ namespace Microsoft.Boogie } } - public static bool CanExpressOldSpecs(Procedure oldProc, Program newProg) + public static bool CanExpressOldSpecs(Procedure oldProc, Program newProg, bool ignoreModifiesClauses = false) { Contract.Requires(oldProc != null && newProg != null); @@ -439,7 +500,7 @@ namespace Microsoft.Boogie var globals = newProg.GlobalVariables; return oldProc.DependenciesCollected && (oldProc.FunctionDependencies == null || oldProc.FunctionDependencies.All(dep => funcs.Any(f => f.Name == dep.Name && f.DependencyChecksum == dep.DependencyChecksum))) - && oldProc.Modifies.All(m => globals.Any(g => g.Name == m.Name)); + && (ignoreModifiesClauses || oldProc.Modifies.All(m => globals.Any(g => g.Name == m.Name))); } public override Procedure VisitProcedure(Procedure node) diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs index 206e0ee7..a19f983a 100644 --- a/Source/VCGeneration/ConditionGeneration.cs +++ b/Source/VCGeneration/ConditionGeneration.cs @@ -768,6 +768,7 @@ namespace VC { Contract.Assert(req != null); Expr e = Substituter.Apply(formalProcImplSubst, req.Condition); Cmd c = new AssumeCmd(req.tok, e); + c.IrrelevantForChecksumComputation = true; insertionPoint.Cmds.Add(c); if (debugWriter != null) { c.Emit(debugWriter, 1); @@ -775,6 +776,11 @@ namespace VC { } origStartBlock.Predecessors.Add(insertionPoint); + if (impl.ExplicitAssumptionAboutCachedPrecondition != null) + { + insertionPoint.Cmds.Add(impl.ExplicitAssumptionAboutCachedPrecondition); + } + if (debugWriter != null) { debugWriter.WriteLine(); } @@ -1275,7 +1281,7 @@ namespace VC { IdentifierExpr v_prime_exp = new IdentifierExpr(v_prime.tok, v_prime); #endregion #region Create the assume command itself - AssumeCmd ac = new AssumeCmd(v.tok, TypedExprEq(v_prime_exp, pred_incarnation_exp, v_prime.Name.Contains("a##post##"))); + AssumeCmd ac = new AssumeCmd(v.tok, TypedExprEq(v_prime_exp, pred_incarnation_exp, v_prime.Name.Contains("a##cached##"))); pred.Cmds.Add(ac); #endregion #endregion @@ -1697,7 +1703,7 @@ namespace VC { } #region Create an assume command with the new variable - assumptions.Add(TypedExprEq(x_prime_exp, copies[i], x_prime_exp.Decl != null && x_prime_exp.Decl.Name.Contains("a##post##"))); + assumptions.Add(TypedExprEq(x_prime_exp, copies[i], x_prime_exp.Decl != null && x_prime_exp.Decl.Name.Contains("a##cached##"))); #endregion } } @@ -1720,6 +1726,7 @@ namespace VC { if (currentImplementation != null && currentImplementation.HasCachedSnapshot && !currentImplementation.AnyErrorsInCachedSnapshot + && currentImplementation.DoomedInjectedAssumptionVariables.Count == 0 && currentImplementation.InjectedAssumptionVariables.Count == 1 && assign.Lhss.Count == 1) { @@ -1744,7 +1751,7 @@ namespace VC { // We do not need to havoc it if we have performed a modular proof of the loop (i.e., using only the loop // invariant) in the previous snapshot and, consequently, the corresponding assumption did not affect the // anything after the loop. We can achieve this by simply not updating/adding it in the incarnation map. - List havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##post##"))).ToList(); + List havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##cached##"))).ToList(); // First, compute the new incarnations foreach (IdentifierExpr ie in havocVars) { Contract.Assert(ie != null); diff --git a/Test/snapshots/Snapshots34.v0.bpl b/Test/snapshots/Snapshots34.v0.bpl new file mode 100644 index 00000000..e3522645 --- /dev/null +++ b/Test/snapshots/Snapshots34.v0.bpl @@ -0,0 +1,7 @@ +procedure {:checksum "0"} P(); + requires 0 != 0; + +implementation {:id "P"} {:checksum "1"} P() +{ + assert 1 != 1; +} diff --git a/Test/snapshots/Snapshots34.v1.bpl b/Test/snapshots/Snapshots34.v1.bpl new file mode 100644 index 00000000..b374f7c0 --- /dev/null +++ b/Test/snapshots/Snapshots34.v1.bpl @@ -0,0 +1,6 @@ +procedure {:checksum "2"} P(); + +implementation {:id "P"} {:checksum "1"} P() +{ + assert 1 != 1; +} diff --git a/Test/snapshots/Snapshots35.v0.bpl b/Test/snapshots/Snapshots35.v0.bpl new file mode 100644 index 00000000..adfd6a69 --- /dev/null +++ b/Test/snapshots/Snapshots35.v0.bpl @@ -0,0 +1,7 @@ +procedure {:checksum "0"} P(b: bool); + requires b; + +implementation {:id "P"} {:checksum "1"} P(p: bool) +{ + assert p; +} diff --git a/Test/snapshots/Snapshots35.v1.bpl b/Test/snapshots/Snapshots35.v1.bpl new file mode 100644 index 00000000..bec381af --- /dev/null +++ b/Test/snapshots/Snapshots35.v1.bpl @@ -0,0 +1,6 @@ +procedure {:checksum "2"} P(b: bool); + +implementation {:id "P"} {:checksum "1"} P(p: bool) +{ + assert p; +} diff --git a/Test/snapshots/runtest.snapshot b/Test/snapshots/runtest.snapshot index a203ffac..01a231fe 100644 --- a/Test/snapshots/runtest.snapshot +++ b/Test/snapshots/runtest.snapshot @@ -1,2 +1,2 @@ -// RUN: %boogie -errorTrace:0 -traceCaching:1 -verifySnapshots:2 -verifySeparately -noinfer Snapshots0.bpl Snapshots1.bpl Snapshots2.bpl Snapshots3.bpl Snapshots4.bpl Snapshots5.bpl Snapshots6.bpl Snapshots7.bpl Snapshots8.bpl Snapshots9.bpl Snapshots10.bpl Snapshots11.bpl Snapshots12.bpl Snapshots13.bpl Snapshots14.bpl Snapshots15.bpl Snapshots16.bpl Snapshots17.bpl Snapshots18.bpl Snapshots19.bpl Snapshots20.bpl Snapshots21.bpl Snapshots22.bpl Snapshots23.bpl Snapshots24.bpl Snapshots25.bpl Snapshots26.bpl Snapshots27.bpl Snapshots28.bpl Snapshots30.bpl Snapshots31.bpl Snapshots32.bpl Snapshots33.bpl > "%t" +// RUN: %boogie -errorTrace:0 -traceCaching:1 -verifySnapshots:2 -verifySeparately -noinfer Snapshots0.bpl Snapshots1.bpl Snapshots2.bpl Snapshots3.bpl Snapshots4.bpl Snapshots5.bpl Snapshots6.bpl Snapshots7.bpl Snapshots8.bpl Snapshots9.bpl Snapshots10.bpl Snapshots11.bpl Snapshots12.bpl Snapshots13.bpl Snapshots14.bpl Snapshots15.bpl Snapshots16.bpl Snapshots17.bpl Snapshots18.bpl Snapshots19.bpl Snapshots20.bpl Snapshots21.bpl Snapshots22.bpl Snapshots23.bpl Snapshots24.bpl Snapshots25.bpl Snapshots26.bpl Snapshots27.bpl Snapshots28.bpl Snapshots30.bpl Snapshots31.bpl Snapshots32.bpl Snapshots33.bpl Snapshots34.bpl Snapshots35.bpl > "%t" // RUN: %diff "%s.expect" "%t" diff --git a/Test/snapshots/runtest.snapshot.expect b/Test/snapshots/runtest.snapshot.expect index 8f3c2015..637dd088 100644 --- a/Test/snapshots/runtest.snapshot.expect +++ b/Test/snapshots/runtest.snapshot.expect @@ -40,8 +40,13 @@ Snapshots1.v1.bpl(13,5): Error BP5001: This assertion might not hold. Boogie program verifier finished with 1 verified, 1 error Processing call to procedure P2 in implementation P1 (at Snapshots1.v2.bpl(5,5)): + >>> added after: a##cached##0 := a##cached##0 && true; +Processing implementation P2 (at Snapshots1.v2.bpl(12,51)): + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && true; Processing command (at Snapshots1.v2.bpl(5,5)) assert false; >>> DoNothingToAssert +Processing command (at ) a##cached##0 := a##cached##0 && true; + >>> AssumeNegationOfAssumptionVariable Snapshots1.v2.bpl(5,5): Error BP5002: A precondition for this call might not hold. Snapshots1.v2.bpl(10,3): Related location: This is the precondition that might not hold. Processing command (at Snapshots1.v2.bpl(14,5)) assert 2 != 2; @@ -52,34 +57,45 @@ Boogie program verifier finished with 1 verified, 1 error Boogie program verifier finished with 1 verified, 0 errors Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P0 (at Snapshots2.v2.bpl(4,51)): + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && true; Processing call to procedure P0 in implementation P0 (at Snapshots2.v2.bpl(6,5)): + >>> added after: a##cached##1 := a##cached##1 && true; Processing command (at Snapshots2.v2.bpl(6,5)) assert F0(); >>> DoNothingToAssert Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P0 (at Snapshots2.v3.bpl(4,51)): + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && false; Processing call to procedure P0 in implementation P0 (at Snapshots2.v3.bpl(6,5)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##1 := a##cached##1 && false; Processing command (at Snapshots2.v3.bpl(6,5)) assert F0(); >>> DoNothingToAssert Boogie program verifier finished with 1 verified, 0 errors Boogie program verifier finished with 1 verified, 0 errors -Processing call to procedure P0 in implementation P0 (at Snapshots2.v5.bpl(7,5)): +Processing implementation P0 (at Snapshots2.v5.bpl(5,51)): >>> added axiom: ##extracted_function##1() == F0() - >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##1(); -Processing command (at Snapshots2.v5.bpl(7,5)) assume {:precondition_previous_snapshot} ##extracted_function##1(); - >>> MarkAsFullyVerified + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && ##extracted_function##1(); +Processing call to procedure P0 in implementation P0 (at Snapshots2.v5.bpl(7,5)): + >>> added axiom: ##extracted_function##2() == F0() + >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##2(); + >>> added after: a##cached##1 := a##cached##1 && true; +Processing command (at Snapshots2.v5.bpl(7,5)) assume {:precondition_previous_snapshot} ##extracted_function##2(); + >>> MarkAsPartiallyVerified Processing command (at Snapshots2.v5.bpl(7,5)) assert F0(); - >>> MarkAsFullyVerified + >>> MarkAsPartiallyVerified Processing command (at Snapshots2.v5.bpl(3,1)) assert F0(); - >>> MarkAsFullyVerified + >>> MarkAsPartiallyVerified Boogie program verifier finished with 1 verified, 0 errors Processing command (at Snapshots3.v0.bpl(2,1)) assert G(); >>> DoNothingToAssert Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P0 (at Snapshots3.v1.bpl(4,51)): + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && false; Processing command (at Snapshots3.v1.bpl(2,1)) assert G(); >>> DoNothingToAssert Snapshots3.v1.bpl(6,1): Error BP5003: A postcondition might not hold on this return path. @@ -89,7 +105,7 @@ Boogie program verifier finished with 0 verified, 1 error Boogie program verifier finished with 3 verified, 0 errors Processing call to procedure P2 in implementation P1 (at Snapshots4.v1.bpl(14,5)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##0 := a##cached##0 && false; Processing command (at Snapshots4.v1.bpl(23,5)) assert false; >>> DoNothingToAssert Snapshots4.v1.bpl(23,5): Error BP5001: This assertion might not hold. @@ -103,6 +119,8 @@ Processing command (at Snapshots5.v0.bpl(5,5)) assert false; >>> DoNothingToAssert Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P0 (at Snapshots5.v1.bpl(3,51)): + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && false; Processing command (at Snapshots5.v1.bpl(5,5)) assert false; >>> DoNothingToAssert Snapshots5.v1.bpl(5,5): Error BP5001: This assertion might not hold. @@ -115,8 +133,8 @@ Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots6.v1.bpl(11,5)): >>> added axiom: (forall y##old##0: int, y: int :: {:weight 30} { ##extracted_function##1(y##old##0, y) } ##extracted_function##1(y##old##0, y) == (y##old##0 == y)) >>> added before: y##old##0 := y; - >>> added after: a##post##0 := a##post##0 && ##extracted_function##1(y##old##0, y); -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##1(y##old##0, y); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##1(y##old##0, y); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(y##old##0, y); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots6.v1.bpl(13,5)) assert y == 0; >>> MarkAsPartiallyVerified @@ -130,8 +148,8 @@ Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots7.v1.bpl(12,5)): >>> added axiom: (forall y: int, z: int :: {:weight 30} { ##extracted_function##1(y, z) } ##extracted_function##1(y, z) == (y < z)) >>> added before: y##old##0 := y; - >>> added after: a##post##0 := a##post##0 && ##extracted_function##1(y, z); -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##1(y, z); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##1(y, z); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(y, z); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots7.v1.bpl(14,5)) assert y < 0; >>> MarkAsPartiallyVerified @@ -147,12 +165,12 @@ Processing call to procedure N in implementation M (at Snapshots8.v1.bpl(8,5)): >>> added axiom: (forall call0formal#AT#n: int :: {:weight 30} { ##extracted_function##1(call0formal#AT#n) } ##extracted_function##1(call0formal#AT#n) == (0 < call0formal#AT#n)) >>> added axiom: (forall call1formal#AT#r: int :: {:weight 30} { ##extracted_function##2(call1formal#AT#r) } ##extracted_function##2(call1formal#AT#r) == (0 < call1formal#AT#r)) >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); - >>> added after: a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); Processing command (at Snapshots8.v1.bpl(8,5)) assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); >>> MarkAsFullyVerified Processing command (at Snapshots8.v1.bpl(8,5)) assert 0 < call0formal#AT#n; >>> MarkAsFullyVerified -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots8.v1.bpl(10,5)) assert 0 <= x; >>> MarkAsPartiallyVerified @@ -170,12 +188,12 @@ Processing call to procedure N in implementation M (at Snapshots9.v1.bpl(8,5)): >>> added axiom: (forall call0formal#AT#n: int :: {:weight 30} { ##extracted_function##1(call0formal#AT#n) } ##extracted_function##1(call0formal#AT#n) == (0 < call0formal#AT#n && true)) >>> added axiom: (forall call1formal#AT#r: int :: {:weight 30} { ##extracted_function##2(call1formal#AT#r) } ##extracted_function##2(call1formal#AT#r) == (0 < call1formal#AT#r && true)) >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); - >>> added after: a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); Processing command (at Snapshots9.v1.bpl(8,5)) assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); >>> MarkAsFullyVerified Processing command (at Snapshots9.v1.bpl(8,5)) assert 0 < call0formal#AT#n; >>> MarkAsFullyVerified -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots9.v1.bpl(10,5)) assert 0 <= x; >>> MarkAsPartiallyVerified @@ -191,12 +209,12 @@ Processing call to procedure N in implementation M (at Snapshots10.v1.bpl(8,5)): >>> added axiom: (forall call0formal#AT#n: int :: {:weight 30} { ##extracted_function##1(call0formal#AT#n) } ##extracted_function##1(call0formal#AT#n) == (0 < call0formal#AT#n)) >>> added axiom: (forall call1formal#AT#r: int :: {:weight 30} { ##extracted_function##2(call1formal#AT#r) } ##extracted_function##2(call1formal#AT#r) == (0 < call1formal#AT#r)) >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); - >>> added after: a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); Processing command (at Snapshots10.v1.bpl(8,5)) assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); >>> MarkAsFullyVerified Processing command (at Snapshots10.v1.bpl(8,5)) assert 0 < call0formal#AT#n; >>> MarkAsFullyVerified -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots10.v1.bpl(12,5)) assert 0 <= x; >>> MarkAsPartiallyVerified @@ -214,7 +232,7 @@ Processing call to procedure N in implementation M (at Snapshots11.v1.bpl(7,5)): >>> added axiom: (forall call0formal#AT#n: int :: {:weight 30} { ##extracted_function##1(call0formal#AT#n) } ##extracted_function##1(call0formal#AT#n) == (0 < call0formal#AT#n)) >>> added axiom: (forall call1formal#AT#r: int :: {:weight 30} { ##extracted_function##2(call1formal#AT#r) } ##extracted_function##2(call1formal#AT#r) == (0 < call1formal#AT#r)) >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); - >>> added after: a##post##0 := a##post##0 && ##extracted_function##2(call1formal#AT#r); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##2(call1formal#AT#r); Processing command (at Snapshots11.v1.bpl(7,5)) assume {:precondition_previous_snapshot} ##extracted_function##1(call0formal#AT#n); >>> DropAssume Processing command (at Snapshots11.v1.bpl(7,5)) assert 0 < call0formal#AT#n; @@ -230,7 +248,7 @@ Processing command (at Snapshots12.v0.bpl(7,5)) assert false; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots12.v1.bpl(5,5)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##0 := a##cached##0 && false; Processing command (at Snapshots12.v1.bpl(7,5)) assert false; >>> DoNothingToAssert Snapshots12.v1.bpl(7,5): Error BP5001: This assertion might not hold. @@ -241,7 +259,7 @@ Processing command (at Snapshots13.v0.bpl(7,5)) assert false; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots13.v1.bpl(5,5)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##0 := a##cached##0 && false; Processing command (at Snapshots13.v1.bpl(7,5)) assert false; >>> DoNothingToAssert Snapshots13.v1.bpl(7,5): Error BP5001: This assertion might not hold. @@ -253,8 +271,8 @@ Processing command (at Snapshots14.v0.bpl(7,5)) assert false; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots14.v1.bpl(5,5)): >>> added axiom: ##extracted_function##1() == (F() && G()) - >>> added after: a##post##0 := a##post##0 && ##extracted_function##1(); -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##1(); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##1(); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots14.v1.bpl(7,5)) assert false; >>> MarkAsPartiallyVerified @@ -270,9 +288,9 @@ Processing command (at Snapshots15.v0.bpl(13,5)) assert false; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots15.v1.bpl(7,5)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##0 := a##cached##0 && false; Processing call to procedure N in implementation M (at Snapshots15.v1.bpl(11,5)): - >>> added after: a##post##1 := a##post##1 && false; + >>> added after: a##cached##1 := a##cached##1 && false; Processing command (at Snapshots15.v1.bpl(5,5)) assert true; >>> MarkAsFullyVerified Processing command (at Snapshots15.v1.bpl(9,5)) assert true; @@ -302,11 +320,11 @@ Processing command (at Snapshots17.v0.bpl(20,13)) assert x == 1; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots17.v1.bpl(14,13)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##0 := a##cached##0 && false; Processing call to procedure N in implementation M (at Snapshots17.v1.bpl(16,13)): - >>> added after: a##post##1 := a##post##1 && false; + >>> added after: a##cached##1 := a##cached##1 && false; Processing call to procedure N in implementation M (at Snapshots17.v1.bpl(23,9)): - >>> added after: a##post##2 := a##post##2 && false; + >>> added after: a##cached##2 := a##cached##2 && false; Processing command (at Snapshots17.v1.bpl(28,5)) assert true; >>> MarkAsFullyVerified Processing command (at Snapshots17.v1.bpl(25,9)) assert false; @@ -328,9 +346,9 @@ Processing command (at Snapshots18.v0.bpl(20,5)) assert 2 != 2; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure N in implementation M (at Snapshots18.v1.bpl(9,9)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##0 := a##cached##0 && false; Processing call to procedure N in implementation M (at Snapshots18.v1.bpl(10,9)): - >>> added after: a##post##1 := a##post##1 && false; + >>> added after: a##cached##1 := a##cached##1 && false; Processing command (at Snapshots18.v1.bpl(7,9)) assert 0 == 0; >>> MarkAsFullyVerified Processing command (at Snapshots18.v1.bpl(17,9)) assert 1 != 1; @@ -351,13 +369,14 @@ Boogie program verifier finished with 0 verified, 1 error Processing call to procedure N in implementation M (at Snapshots19.v1.bpl(5,5)): >>> added axiom: ##extracted_function##1() == (2 == 2) >>> added before precondition check: assume {:precondition_previous_snapshot} ##extracted_function##1(); + >>> added after: a##cached##0 := a##cached##0 && true; Processing command (at Snapshots19.v1.bpl(5,5)) assume {:precondition_previous_snapshot} ##extracted_function##1(); >>> MarkAsFullyVerified Processing command (at Snapshots19.v1.bpl(5,5)) assert 2 == 2; >>> MarkAsFullyVerified Processing command (at Snapshots19.v1.bpl(7,5)) assert 1 != 1; - >>> RecycleError -Snapshots19.v0.bpl(7,5): Error BP5001: This assertion might not hold. + >>> DoNothingToAssert +Snapshots19.v1.bpl(7,5): Error BP5001: This assertion might not hold. Boogie program verifier finished with 0 verified, 1 error Processing command (at Snapshots20.v0.bpl(9,9)) assert 1 != 1; @@ -371,7 +390,7 @@ Snapshots20.v0.bpl(13,9): Error BP5001: This assertion might not hold. Boogie program verifier finished with 0 verified, 1 error Processing call to procedure N in implementation M (at Snapshots20.v1.bpl(7,9)): >>> added axiom: ##extracted_function##1() == (0 != 0) - >>> added after: a##post##0 := a##post##0 && ##extracted_function##1(); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##1(); Processing command (at Snapshots20.v1.bpl(9,9)) assert 1 != 1; >>> MarkAsPartiallyVerified Processing command (at Snapshots20.v1.bpl(13,9)) assert 2 != 2; @@ -567,8 +586,8 @@ Processing command (at Snapshots31.v0.bpl(10,5)) assert 0 < g; Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure Q in implementation P (at Snapshots31.v1.bpl(9,5)): >>> added axiom: (forall call0old#AT#g: int, g: int :: {:weight 30} { ##extracted_function##1(call0old#AT#g, g) } ##extracted_function##1(call0old#AT#g, g) == (call0old#AT#g < g)) - >>> added after: a##post##0 := a##post##0 && ##extracted_function##1(call0old#AT#g, g); -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##1(call0old#AT#g, g); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##1(call0old#AT#g, g); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(call0old#AT#g, g); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots31.v1.bpl(10,5)) assert 0 < g; >>> MarkAsPartiallyVerified @@ -582,8 +601,8 @@ Boogie program verifier finished with 1 verified, 0 errors Processing call to procedure Q in implementation P (at Snapshots32.v1.bpl(8,5)): >>> added axiom: (forall g##old##0: int, g: int :: {:weight 30} { ##extracted_function##1(g##old##0, g) } ##extracted_function##1(g##old##0, g) == (g##old##0 < g)) >>> added before: g##old##0 := g; - >>> added after: a##post##0 := a##post##0 && ##extracted_function##1(g##old##0, g); -Processing command (at ) a##post##0 := a##post##0 && ##extracted_function##1(g##old##0, g); + >>> added after: a##cached##0 := a##cached##0 && ##extracted_function##1(g##old##0, g); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(g##old##0, g); >>> AssumeNegationOfAssumptionVariable Processing command (at Snapshots32.v1.bpl(9,5)) assert 0 < g; >>> MarkAsPartiallyVerified @@ -594,7 +613,38 @@ Processing command (at Snapshots33.v0.bpl(10,5)) assert 0 < g; >>> DoNothingToAssert Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P (at Snapshots33.v1.bpl(3,42)): + >>> added axiom: (forall g: int :: {:weight 30} { ##extracted_function##1(g) } ##extracted_function##1(g) == (g == 0)) + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && ##extracted_function##1(g); Processing call to procedure Q in implementation P (at Snapshots33.v1.bpl(5,5)): - >>> added after: a##post##0 := a##post##0 && false; + >>> added after: a##cached##1 := a##cached##1 && false; + +Boogie program verifier finished with 1 verified, 0 errors +Processing command (at Snapshots34.v0.bpl(6,5)) assert 1 != 1; + >>> DoNothingToAssert + +Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P (at Snapshots34.v1.bpl(3,42)): + >>> added axiom: ##extracted_function##1() == (0 != 0) + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && ##extracted_function##1(); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(); + >>> AssumeNegationOfAssumptionVariable +Processing command (at Snapshots34.v1.bpl(5,5)) assert 1 != 1; + >>> MarkAsPartiallyVerified +Snapshots34.v1.bpl(5,5): Error BP5001: This assertion might not hold. + +Boogie program verifier finished with 0 verified, 1 error +Processing command (at Snapshots35.v0.bpl(6,5)) assert p; + >>> DoNothingToAssert Boogie program verifier finished with 1 verified, 0 errors +Processing implementation P (at Snapshots35.v1.bpl(3,42)): + >>> added axiom: (forall p: bool :: {:weight 30} { ##extracted_function##1(p) } ##extracted_function##1(p) == p) + >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && ##extracted_function##1(p); +Processing command (at ) a##cached##0 := a##cached##0 && ##extracted_function##1(p); + >>> AssumeNegationOfAssumptionVariable +Processing command (at Snapshots35.v1.bpl(5,5)) assert p; + >>> MarkAsPartiallyVerified +Snapshots35.v1.bpl(5,5): Error BP5001: This assertion might not hold. + +Boogie program verifier finished with 0 verified, 1 error -- cgit v1.2.3 From b8984d6c6d7495f19c70bbc1e3a364f8b0a4e206 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Sun, 17 May 2015 13:42:49 +0200 Subject: Minor refactoring --- Source/Core/AbsyCmd.cs | 15 --------------- Source/ExecutionEngine/VerificationResultCache.cs | 11 +++++++++-- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs index eb8b8e1e..f659f9ea 100644 --- a/Source/Core/AbsyCmd.cs +++ b/Source/Core/AbsyCmd.cs @@ -1529,18 +1529,6 @@ namespace Microsoft.Boogie { } public override void Emit(TokenTextWriter stream, int level) { - if (stream.UseForComputingChecksums) - { - var lhs = Lhss.FirstOrDefault() as SimpleAssignLhs; - if (lhs != null - && lhs.AssignedVariable.Decl != null - && (QKeyValue.FindBoolAttribute(lhs.AssignedVariable.Decl.Attributes, "assumption") - || lhs.AssignedVariable.Decl.Name.Contains("##old##"))) - { - return; - } - } - stream.Write(this, level, ""); string/*!*/ sep = ""; @@ -3213,9 +3201,6 @@ namespace Microsoft.Boogie { } public override void Emit(TokenTextWriter stream, int level) { //Contract.Requires(stream != null); - - if (stream.UseForComputingChecksums && QKeyValue.FindBoolAttribute(Attributes, "precondition_previous_snapshot")) { return; } - stream.Write(this, level, "assume "); EmitAttributes(stream, Attributes); this.Expr.Emit(stream); diff --git a/Source/ExecutionEngine/VerificationResultCache.cs b/Source/ExecutionEngine/VerificationResultCache.cs index 63e88dfe..cfbd5285 100644 --- a/Source/ExecutionEngine/VerificationResultCache.cs +++ b/Source/ExecutionEngine/VerificationResultCache.cs @@ -126,6 +126,7 @@ namespace Microsoft.Boogie var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, lv)); var rhs = LiteralExpr.And(new IdentifierExpr(Token.NoToken, lv), assumedExpr); var assumed = new AssignCmd(currentImplementation.tok, new List { lhs }, new List { rhs }); + assumed.IrrelevantForChecksumComputation = true; currentImplementation.ExplicitAssumptionAboutCachedPrecondition = assumed; after.Add(assumed); } @@ -257,6 +258,7 @@ namespace Microsoft.Boogie if (precond != null) { var assume = new AssumeCmd(node.tok, precond, new QKeyValue(Token.NoToken, "precondition_previous_snapshot", new List(), null)); + assume.IrrelevantForChecksumComputation = true; beforePrecondtionCheck.Add(assume); } @@ -268,7 +270,9 @@ namespace Microsoft.Boogie new TypedIdent(Token.NoToken, string.Format("{0}##old##{1}", unmod.Name, FreshTemporaryVariableName), unmod.Type)); var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, oldUnmod)); var rhs = new IdentifierExpr(Token.NoToken, unmod.Decl); - before.Add(new AssignCmd(Token.NoToken, new List { lhs }, new List { rhs })); + var cmd = new AssignCmd(Token.NoToken, new List { lhs }, new List { rhs }); + cmd.IrrelevantForChecksumComputation = true; + before.Add(cmd); var eq = LiteralExpr.Eq(new IdentifierExpr(Token.NoToken, oldUnmod), new IdentifierExpr(Token.NoToken, unmod.Decl)); eq.Type = Type.Bool; eq.TypeParameters = SimpleTypeParamInstantiation.EMPTY; @@ -284,7 +288,9 @@ namespace Microsoft.Boogie oldSubst[mod.Decl] = new IdentifierExpr(Token.NoToken, oldMod); var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, oldMod)); var rhs = new IdentifierExpr(Token.NoToken, mod.Decl); - before.Add(new AssignCmd(Token.NoToken, new List { lhs }, new List { rhs })); + var cmd = new AssignCmd(Token.NoToken, new List { lhs }, new List { rhs }); + cmd.IrrelevantForChecksumComputation = true; + before.Add(cmd); } assumedExpr = node.Postcondition(oldProc, eqs, oldSubst, Program, e => FunctionExtractor.Extract(e, Program, axioms)); @@ -304,6 +310,7 @@ namespace Microsoft.Boogie var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, lv)); var rhs = LiteralExpr.And(new IdentifierExpr(Token.NoToken, lv), assumedExpr); var assumed = new AssignCmd(node.tok, new List { lhs }, new List { rhs }); + assumed.IrrelevantForChecksumComputation = true; after.Add(assumed); } -- cgit v1.2.3 From 216c71366e6fff4e225b68ef6ff69035c9542b4a Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Mon, 18 May 2015 18:19:13 +0200 Subject: Add some experimental support for diagnosing timeouts. --- Source/Core/CommandLineOptions.cs | 2 + Source/Provers/SMTLib/ProverInterface.cs | 158 +++++++++++++++++++++++++++++++ Source/VCExpr/VCExprAST.cs | 2 + Source/VCGeneration/Check.cs | 2 +- Source/VCGeneration/Context.cs | 2 + Source/VCGeneration/StratifiedVC.cs | 2 +- Source/VCGeneration/VC.cs | 10 +- Source/VCGeneration/Wlp.cs | 11 +++ 8 files changed, 186 insertions(+), 3 deletions(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index dbbb6fd0..03545cbf 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -557,6 +557,7 @@ namespace Microsoft.Boogie { public bool UseSmtOutputFormat = false; public bool WeakArrayTheory = false; public bool UseLabels = true; + public bool RunDiagnosticsOnTimeout = false; public bool SIBoolControlVC = false; public bool MonomorphicArrays { get { @@ -1585,6 +1586,7 @@ namespace Microsoft.Boogie { ps.CheckBooleanFlag("weakArrayTheory", ref WeakArrayTheory) || ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) || ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false) || + ps.CheckBooleanFlag("runDiagnosticsOnTimeout", ref RunDiagnosticsOnTimeout) || ps.CheckBooleanFlag("boolControlVC", ref SIBoolControlVC, true) || ps.CheckBooleanFlag("contractInfer", ref ContractInfer) || ps.CheckBooleanFlag("explainHoudini", ref ExplainHoudini) || diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index 868b9ee3..4a9ba929 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -30,6 +30,8 @@ namespace Microsoft.Boogie.SMTLib private readonly SMTLibProverOptions options; private bool usingUnsatCore; private RPFP rpfp = null; + private string currentVC; + private string currentDescriptiveName; [ContractInvariantMethod] void ObjectInvariant() @@ -261,6 +263,11 @@ namespace Microsoft.Boogie.SMTLib SendCommon("(assert (and (tickleBool true) (tickleBool false)))"); } + if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout) + { + SendCommon("(declare-fun timeoutDiagnostics (Int) Bool)"); + } + if (ctx.KnownDatatypeConstructors.Count > 0) { GraphUtil.Graph dependencyGraph = new GraphUtil.Graph(); @@ -393,7 +400,10 @@ namespace Microsoft.Boogie.SMTLib } PrepareCommon(); + string vcString = "(assert (not\n" + VCExpr2String(vc, 1) + "\n))"; + currentVC = vcString; + currentDescriptiveName = descriptiveName; FlushAxioms(); PossiblyRestart(); @@ -1246,6 +1256,7 @@ namespace Microsoft.Boogie.SMTLib var globalResult = Outcome.Undetermined; while (true) { + bool popLater = false; errorsLeft--; string[] labels = null; @@ -1254,6 +1265,111 @@ namespace Microsoft.Boogie.SMTLib globalResult = result; if (result == Outcome.Invalid || result == Outcome.TimeOut || result == Outcome.OutOfMemory) { + + if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout && (result == Outcome.TimeOut || result == Outcome.OutOfMemory)) + { + SendThisVC("; begin timeout diagnostics"); + + var verified = new bool[Context.TimoutDiagnosticsCount]; + var lastCnt = verified.Length + 1; + var mod = 2; + while (true) + { + var split0 = verified.ToArray(); + var split1 = verified.ToArray(); + int cnt0 = 0; + int cnt1 = 0; + for (int i = 0; i < split0.Length; i++) + { + if (!split0[i]) + { + // TODO(wuestholz): Try out different ways for splitting up the work. + if ((cnt0 + cnt1) % mod == 0) + { + split0[i] = true; + cnt1++; + } + else + { + split1[i] = true; + cnt0++; + } + } + } + + bool doReset = false; + var cnt = cnt0 + cnt1; + if (cnt == 0) + { + return Outcome.Valid; + } + else if (lastCnt <= cnt) + { + doReset = true; + if (mod < cnt) + { + mod++; + } + else + { + // Give up and report which assertions were not verified. + var cmds = new List>(); + for (int i = 0; i < verified.Length; i++) + { + if (!verified[i]) + { + cmds.Add(ctx.TimeoutDiagnosticIDToAssertion[i]); + } + } + + if (cmds.Any()) + { + handler.OnResourceExceeded("timeout after running diagnostics", cmds); + } + + break; + } + } + lastCnt = cnt; + + if (0 < cnt0) + { + var result0 = CheckSplit(split0, cnt0, ref popLater, doReset); + if (result0 == Outcome.Valid) + { + for (int i = 0; i < split0.Length; i++) + { + verified[i] = verified[i] || !split0[i]; + } + } + else if (result0 == Outcome.Invalid) + { + result = result0; + break; + } + } + + if (0 < cnt1) + { + var result1 = CheckSplit(split1, cnt1, ref popLater, doReset); + if (result1 == Outcome.Valid) + { + for (int i = 0; i < split1.Length; i++) + { + verified[i] = verified[i] || !split1[i]; + } + } + else if (result1 == Outcome.Invalid) + { + result = result1; + break; + } + } + } + + SendThisVC("; end timeout diagnostics"); + } + IList xlabels; if (CommandLineOptions.Clo.UseLabels) { labels = GetLabelsInfo(); @@ -1301,6 +1417,11 @@ namespace Microsoft.Boogie.SMTLib SendThisVC("(assert (not (= (ControlFlow 0 " + source + ") (- " + target + "))))"); SendThisVC("(check-sat)"); } + + if (popLater) + { + SendThisVC("(pop 1)"); + } } FlushLogFile(); @@ -1315,6 +1436,43 @@ namespace Microsoft.Boogie.SMTLib } } + private Outcome CheckSplit(bool[] split, int unverifiedCount, ref bool popLater, bool doReset = false) + { + if (doReset) + { + Reset(gen); + PossiblyRestart(); + SendThisVC("(push 1)"); + SendThisVC("(set-info :boogie-vc-id " + SMTLibNamer.QuoteId(currentDescriptiveName) + ")"); + SendThisVC(currentVC); + popLater = false; + } + else + { + if (popLater) + { + SendThisVC("(pop 1)"); + } + SendThisVC("(push 1)"); + SendThisVC(string.Format("(set-option :{0} {1})", Z3.SetTimeoutOption(), options.TimeLimit)); + popLater = true; + } + SendThisVC(string.Format("; checking split VC with {0} unverified assertions", unverifiedCount)); + var expr = VCExpressionGenerator.True; + for (int i = 0; i < split.Length; i++) + { + var lit = VCExprGen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, VCExprGen.Integer(Microsoft.Basetypes.BigNum.FromInt(i))); + if (!split[i]) { + lit = VCExprGen.Not(lit); + } + expr = VCExprGen.AndSimp(expr, lit); + } + SendThisVC("(assert " + VCExpr2String(expr, 1) + ")"); + FlushLogFile(); + SendThisVC("(check-sat)"); + return GetResponse(); + } + public override string[] CalculatePath(int controlFlowConstant) { SendThisVC("(get-value ((ControlFlow " + controlFlowConstant + " 0)))"); var path = new List(); diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs index 4f8dc08e..15573f5b 100644 --- a/Source/VCExpr/VCExprAST.cs +++ b/Source/VCExpr/VCExprAST.cs @@ -339,6 +339,8 @@ namespace Microsoft.Boogie { public static readonly VCExprOp TickleBoolOp = new VCExprCustomOp("tickleBool", 1, Type.Bool); + public static readonly VCExprOp TimeoutDiagnosticsOp = new VCExprCustomOp("timeoutDiagnostics", 1, Type.Bool); + public VCExprOp BoogieFunctionOp(Function func) { Contract.Requires(func != null); Contract.Ensures(Contract.Result() != null); diff --git a/Source/VCGeneration/Check.cs b/Source/VCGeneration/Check.cs index da8624e9..7c690eff 100644 --- a/Source/VCGeneration/Check.cs +++ b/Source/VCGeneration/Check.cs @@ -461,7 +461,7 @@ namespace Microsoft.Boogie { Contract.Requires(cce.NonNullElements(labels)); } - public virtual void OnResourceExceeded(string message) { + public virtual void OnResourceExceeded(string message, IEnumerable> assertCmds = null) { Contract.Requires(message != null); } diff --git a/Source/VCGeneration/Context.cs b/Source/VCGeneration/Context.cs index 83787dc5..ddc34976 100644 --- a/Source/VCGeneration/Context.cs +++ b/Source/VCGeneration/Context.cs @@ -22,6 +22,8 @@ namespace Microsoft.Boogie /// [ContractClass(typeof(ProverContextContracts))] public abstract class ProverContext : ICloneable { + public int TimoutDiagnosticsCount { get; set; } + public readonly Dictionary> TimeoutDiagnosticIDToAssertion = new Dictionary>(); protected virtual void ProcessDeclaration(Declaration decl) {Contract.Requires(decl != null);} public virtual void DeclareType(TypeCtorDecl t, string attributes) {Contract.Requires(t != null); ProcessDeclaration(t); } public virtual void DeclareConstant(Constant c, bool uniq, string attributes) {Contract.Requires(c != null); ProcessDeclaration(c); } diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index e88eb55e..69b7c8cc 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -2273,7 +2273,7 @@ namespace VC { return; } - public override void OnResourceExceeded(string message) + public override void OnResourceExceeded(string message, IEnumerable> assertCmds = null) { //Contract.Requires(message != null); } diff --git a/Source/VCGeneration/VC.cs b/Source/VCGeneration/VC.cs index 560f55b4..3a483a58 100644 --- a/Source/VCGeneration/VC.cs +++ b/Source/VCGeneration/VC.cs @@ -2096,9 +2096,17 @@ namespace VC { return cce.NonNull((Absy)label2absy[id]); } - public override void OnResourceExceeded(string msg) { + public override void OnResourceExceeded(string msg, IEnumerable> assertCmds = null) { //Contract.Requires(msg != null); resourceExceededMessage = msg; + if (assertCmds != null) + { + foreach (var cmd in assertCmds) + { + Counterexample cex = AssertCmdToCounterexample(cmd.Item1, cmd.Item2 , new List(), null, null, context); + callback.OnCounterexample(cex, msg); + } + } } public override void OnProverWarning(string msg) { diff --git a/Source/VCGeneration/Wlp.cs b/Source/VCGeneration/Wlp.cs index 45e511f0..82d3b607 100644 --- a/Source/VCGeneration/Wlp.cs +++ b/Source/VCGeneration/Wlp.cs @@ -118,6 +118,17 @@ namespace VC { if (ac.VerifiedUnder != null) { VU = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.VerifiedUnder); + + if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout) + { + ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple(ac, b.TransferCmd); + VU = gen.Or(VU, gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++)))); + } + } + else if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout) + { + ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple(ac, b.TransferCmd); + VU = gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++))); } ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext; } -- cgit v1.2.3 From 01829aa2ff554cea60e51b38b4ab1be41cc7ee57 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Mon, 18 May 2015 23:39:48 +0200 Subject: Make it not return cached verification results for timed-out implementations when timeout diagnostics are enabled. --- Source/ExecutionEngine/VerificationResultCache.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/ExecutionEngine/VerificationResultCache.cs b/Source/ExecutionEngine/VerificationResultCache.cs index cfbd5285..a18cee05 100644 --- a/Source/ExecutionEngine/VerificationResultCache.cs +++ b/Source/ExecutionEngine/VerificationResultCache.cs @@ -667,6 +667,10 @@ namespace Microsoft.Boogie { priority = Priority.LOW; } + else if (result.Outcome == ConditionGeneration.Outcome.TimedOut && CommandLineOptions.Clo.RunDiagnosticsOnTimeout) + { + priority = Priority.MEDIUM; + } else { priority = Priority.SKIP; -- cgit v1.2.3 From 42962744c4f9a403bba0a6fdf879cc2bd5af2afc Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Tue, 19 May 2015 19:26:57 +0200 Subject: Improve support for diagnosing timeouts. --- Source/Provers/SMTLib/ProverInterface.cs | 245 ++++++++++++++++--------------- 1 file changed, 127 insertions(+), 118 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index 4a9ba929..e4691a4b 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1242,160 +1242,174 @@ namespace Microsoft.Boogie.SMTLib currentErrorHandler = handler; FlushProverWarnings(); - int errorsLeft; + int errorLimit; if (CommandLineOptions.Clo.ConcurrentHoudini) { Contract.Assert(taskID >= 0); - errorsLeft = CommandLineOptions.Clo.Cho[taskID].ProverCCLimit; + errorLimit = CommandLineOptions.Clo.Cho[taskID].ProverCCLimit; } else { - errorsLeft = CommandLineOptions.Clo.ProverCCLimit; + errorLimit = CommandLineOptions.Clo.ProverCCLimit; } - if (errorsLeft < 1) - errorsLeft = 1; + if (errorLimit < 1) + errorLimit = 1; + + int errorsLeft = errorLimit; var globalResult = Outcome.Undetermined; while (true) { - bool popLater = false; - errorsLeft--; string[] labels = null; + bool popLater = false; - result = GetResponse(); - if (globalResult == Outcome.Undetermined) - globalResult = result; - - if (result == Outcome.Invalid || result == Outcome.TimeOut || result == Outcome.OutOfMemory) { - - if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout && (result == Outcome.TimeOut || result == Outcome.OutOfMemory)) - { - SendThisVC("; begin timeout diagnostics"); - - var verified = new bool[Context.TimoutDiagnosticsCount]; - var lastCnt = verified.Length + 1; - var mod = 2; - while (true) + try { + errorsLeft--; + + result = GetResponse(); + if (globalResult == Outcome.Undetermined) + globalResult = result; + + if (result == Outcome.Invalid || result == Outcome.TimeOut || result == Outcome.OutOfMemory) { + + if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout && result == Outcome.TimeOut) { - var split0 = verified.ToArray(); - var split1 = verified.ToArray(); - int cnt0 = 0; - int cnt1 = 0; - for (int i = 0; i < split0.Length; i++) + #region Run timeout diagnostics + + SendThisVC("; begin timeout diagnostics"); + + var verified = new bool[Context.TimoutDiagnosticsCount]; + var lastCnt = verified.Length + 1; + var mod = 2; + while (true) { - if (!split0[i]) + var split0 = verified.ToArray(); + var split1 = verified.ToArray(); + int cnt0 = 0; + int cnt1 = 0; + for (int i = 0; i < split0.Length; i++) { - // TODO(wuestholz): Try out different ways for splitting up the work. - if ((cnt0 + cnt1) % mod == 0) + if (!split0[i]) { - split0[i] = true; - cnt1++; + // TODO(wuestholz): Try out different ways for splitting up the work. + if ((cnt0 + cnt1) % mod == 0) + { + split0[i] = true; + cnt1++; + } + else + { + split1[i] = true; + cnt0++; + } + } + } + + bool doReset = false; + var cnt = cnt0 + cnt1; + if (cnt == 0) + { + return Outcome.Valid; + } + else if (lastCnt <= cnt) + { + doReset = (errorLimit == errorsLeft + 1); + if (mod < cnt) + { + mod++; } else { - split1[i] = true; - cnt0++; + // Give up and report which assertions were not verified. + var cmds = new List>(); + for (int i = 0; i < verified.Length; i++) + { + if (!verified[i]) + { + cmds.Add(ctx.TimeoutDiagnosticIDToAssertion[i]); + } + } + + if (cmds.Any()) + { + handler.OnResourceExceeded("timeout after running diagnostics", cmds); + } + + break; } } - } - - bool doReset = false; - var cnt = cnt0 + cnt1; - if (cnt == 0) - { - return Outcome.Valid; - } - else if (lastCnt <= cnt) - { - doReset = true; - if (mod < cnt) - { - mod++; - } - else + lastCnt = cnt; + + if (0 < cnt0) { - // Give up and report which assertions were not verified. - var cmds = new List>(); - for (int i = 0; i < verified.Length; i++) + var result0 = CheckSplit(split0, cnt0, ref popLater, doReset); + if (result0 == Outcome.Valid) { - if (!verified[i]) + for (int i = 0; i < split0.Length; i++) { - cmds.Add(ctx.TimeoutDiagnosticIDToAssertion[i]); + verified[i] = verified[i] || !split0[i]; } } - - if (cmds.Any()) + else if (result0 == Outcome.Invalid) { - handler.OnResourceExceeded("timeout after running diagnostics", cmds); + result = result0; + break; } - - break; } - } - lastCnt = cnt; - - if (0 < cnt0) - { - var result0 = CheckSplit(split0, cnt0, ref popLater, doReset); - if (result0 == Outcome.Valid) + + if (0 < cnt1) { - for (int i = 0; i < split0.Length; i++) + var result1 = CheckSplit(split1, cnt1, ref popLater, doReset); + if (result1 == Outcome.Valid) { - verified[i] = verified[i] || !split0[i]; + for (int i = 0; i < split1.Length; i++) + { + verified[i] = verified[i] || !split1[i]; + } } - } - else if (result0 == Outcome.Invalid) - { - result = result0; - break; - } - } - - if (0 < cnt1) - { - var result1 = CheckSplit(split1, cnt1, ref popLater, doReset); - if (result1 == Outcome.Valid) - { - for (int i = 0; i < split1.Length; i++) + else if (result1 == Outcome.Invalid) { - verified[i] = verified[i] || !split1[i]; + result = result1; + break; } } - else if (result1 == Outcome.Invalid) - { - result = result1; - break; - } } - } - - SendThisVC("; end timeout diagnostics"); - } + + SendThisVC("; end timeout diagnostics"); - IList xlabels; - if (CommandLineOptions.Clo.UseLabels) { - labels = GetLabelsInfo(); - if (labels == null) - { - xlabels = new string[] { }; + #endregion } - else - { - xlabels = labels.Select(a => a.Replace("@", "").Replace("+", "")).ToList(); + + IList xlabels; + if (CommandLineOptions.Clo.UseLabels) { + labels = GetLabelsInfo(); + if (labels == null) + { + xlabels = new string[] { }; + } + else + { + xlabels = labels.Select(a => a.Replace("@", "").Replace("+", "")).ToList(); + } } - } - else if(CommandLineOptions.Clo.SIBoolControlVC) { - labels = new string[0]; + else if(CommandLineOptions.Clo.SIBoolControlVC) { + labels = new string[0]; + xlabels = labels; + } else { + labels = CalculatePath(handler.StartingProcId()); xlabels = labels; - } else { - labels = CalculatePath(handler.StartingProcId()); - xlabels = labels; + } + Model model = (result == Outcome.TimeOut || result == Outcome.OutOfMemory) ? null : + GetErrorModel(); + handler.OnModel(xlabels, model, result); + } + + if (labels == null || !labels.Any() || errorsLeft == 0) break; + } finally { + if (popLater) + { + SendThisVC("(pop 1)"); } - Model model = (result == Outcome.TimeOut || result == Outcome.OutOfMemory) ? null : - GetErrorModel(); - handler.OnModel(xlabels, model, result); } - if (labels == null || !labels.Any() || errorsLeft == 0) break; - if (CommandLineOptions.Clo.UseLabels) { var negLabels = labels.Where(l => l.StartsWith("@")).ToArray(); var posLabels = labels.Where(l => !l.StartsWith("@")); @@ -1417,11 +1431,6 @@ namespace Microsoft.Boogie.SMTLib SendThisVC("(assert (not (= (ControlFlow 0 " + source + ") (- " + target + "))))"); SendThisVC("(check-sat)"); } - - if (popLater) - { - SendThisVC("(pop 1)"); - } } FlushLogFile(); @@ -1438,7 +1447,7 @@ namespace Microsoft.Boogie.SMTLib private Outcome CheckSplit(bool[] split, int unverifiedCount, ref bool popLater, bool doReset = false) { - if (doReset) + if (doReset && currentVC != null && currentDescriptiveName != null) { Reset(gen); PossiblyRestart(); -- cgit v1.2.3 From bc5b252f0760be84bf96edc2750b85fb0238e772 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Wed, 20 May 2015 13:15:01 +0200 Subject: Improve support for diagnosing timeouts. --- Source/Provers/SMTLib/ProverInterface.cs | 208 +++++++++++++++---------------- 1 file changed, 100 insertions(+), 108 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index e4691a4b..ac804b31 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -30,8 +30,6 @@ namespace Microsoft.Boogie.SMTLib private readonly SMTLibProverOptions options; private bool usingUnsatCore; private RPFP rpfp = null; - private string currentVC; - private string currentDescriptiveName; [ContractInvariantMethod] void ObjectInvariant() @@ -402,8 +400,6 @@ namespace Microsoft.Boogie.SMTLib PrepareCommon(); string vcString = "(assert (not\n" + VCExpr2String(vc, 1) + "\n))"; - currentVC = vcString; - currentDescriptiveName = descriptiveName; FlushAxioms(); PossiblyRestart(); @@ -1265,119 +1261,125 @@ namespace Microsoft.Boogie.SMTLib errorsLeft--; result = GetResponse(); - if (globalResult == Outcome.Undetermined) - globalResult = result; - - if (result == Outcome.Invalid || result == Outcome.TimeOut || result == Outcome.OutOfMemory) { - - if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout && result == Outcome.TimeOut) - { - #region Run timeout diagnostics - SendThisVC("; begin timeout diagnostics"); - - var verified = new bool[Context.TimoutDiagnosticsCount]; - var lastCnt = verified.Length + 1; - var mod = 2; - while (true) + if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout && result == Outcome.TimeOut) + { + #region Run timeout diagnostics + + SendThisVC("; begin timeout diagnostics"); + + var verified = new bool[Context.TimoutDiagnosticsCount]; + var lastCnt = verified.Length + 1; + var mod = 2; + var timeLimit = options.TimeLimit; + var timeLimitFactor = 1; + while (true) + { + var split0 = verified.ToArray(); + var split1 = verified.ToArray(); + int cnt0 = 0; + int cnt1 = 0; + for (int i = 0; i < split0.Length; i++) { - var split0 = verified.ToArray(); - var split1 = verified.ToArray(); - int cnt0 = 0; - int cnt1 = 0; - for (int i = 0; i < split0.Length; i++) + if (!split0[i]) { - if (!split0[i]) + // TODO(wuestholz): Try out different ways for splitting up the work. + if ((cnt0 + cnt1) % mod == 0) { - // TODO(wuestholz): Try out different ways for splitting up the work. - if ((cnt0 + cnt1) % mod == 0) - { - split0[i] = true; - cnt1++; - } - else - { - split1[i] = true; - cnt0++; - } + split0[i] = true; + cnt1++; + } + else + { + split1[i] = true; + cnt0++; } } - - bool doReset = false; - var cnt = cnt0 + cnt1; - if (cnt == 0) + } + + var cnt = cnt0 + cnt1; + if (cnt == 0) + { + result = Outcome.Valid; + break; + } + else if (lastCnt <= cnt) + { + if (mod < cnt) { - return Outcome.Valid; + mod++; } - else if (lastCnt <= cnt) + else if (timeLimitFactor <= 3 && 0 < timeLimit) { - doReset = (errorLimit == errorsLeft + 1); - if (mod < cnt) - { - mod++; - } - else - { - // Give up and report which assertions were not verified. - var cmds = new List>(); - for (int i = 0; i < verified.Length; i++) - { - if (!verified[i]) - { - cmds.Add(ctx.TimeoutDiagnosticIDToAssertion[i]); - } - } - - if (cmds.Any()) - { - handler.OnResourceExceeded("timeout after running diagnostics", cmds); - } - - break; - } + // TODO(wuestholz): Add a commandline option to control this. + timeLimitFactor++; } - lastCnt = cnt; - - if (0 < cnt0) + else { - var result0 = CheckSplit(split0, cnt0, ref popLater, doReset); - if (result0 == Outcome.Valid) + // Give up and report which assertions were not verified. + var cmds = new List>(); + for (int i = 0; i < verified.Length; i++) { - for (int i = 0; i < split0.Length; i++) + if (!verified[i]) { - verified[i] = verified[i] || !split0[i]; + cmds.Add(ctx.TimeoutDiagnosticIDToAssertion[i]); } } - else if (result0 == Outcome.Invalid) + + if (cmds.Any()) { - result = result0; - break; + handler.OnResourceExceeded("timeout after running diagnostics", cmds); } + + break; } - - if (0 < cnt1) + } + lastCnt = cnt; + + if (0 < cnt0) + { + var result0 = CheckSplit(split0, cnt0, ref popLater, timeLimitFactor * timeLimit); + if (result0 == Outcome.Valid) { - var result1 = CheckSplit(split1, cnt1, ref popLater, doReset); - if (result1 == Outcome.Valid) + for (int i = 0; i < split0.Length; i++) { - for (int i = 0; i < split1.Length; i++) - { - verified[i] = verified[i] || !split1[i]; - } + verified[i] = verified[i] || !split0[i]; } - else if (result1 == Outcome.Invalid) + } + else if (result0 == Outcome.Invalid) + { + result = result0; + break; + } + } + + if (0 < cnt1) + { + var result1 = CheckSplit(split1, cnt1, ref popLater, timeLimitFactor * timeLimit); + if (result1 == Outcome.Valid) + { + for (int i = 0; i < split1.Length; i++) { - result = result1; - break; + verified[i] = verified[i] || !split1[i]; } } + else if (result1 == Outcome.Invalid) + { + result = result1; + break; + } } - - SendThisVC("; end timeout diagnostics"); - - #endregion } + + SendThisVC("; end timeout diagnostics"); + + #endregion + } + + if (globalResult == Outcome.Undetermined) + globalResult = result; + if (result == Outcome.Invalid || result == Outcome.TimeOut || result == Outcome.OutOfMemory) { IList xlabels; if (CommandLineOptions.Clo.UseLabels) { labels = GetLabelsInfo(); @@ -1445,27 +1447,17 @@ namespace Microsoft.Boogie.SMTLib } } - private Outcome CheckSplit(bool[] split, int unverifiedCount, ref bool popLater, bool doReset = false) + private Outcome CheckSplit(bool[] split, int unverifiedCount, ref bool popLater, int timeLimit) { - if (doReset && currentVC != null && currentDescriptiveName != null) + if (popLater) { - Reset(gen); - PossiblyRestart(); - SendThisVC("(push 1)"); - SendThisVC("(set-info :boogie-vc-id " + SMTLibNamer.QuoteId(currentDescriptiveName) + ")"); - SendThisVC(currentVC); - popLater = false; - } - else - { - if (popLater) - { - SendThisVC("(pop 1)"); - } - SendThisVC("(push 1)"); - SendThisVC(string.Format("(set-option :{0} {1})", Z3.SetTimeoutOption(), options.TimeLimit)); - popLater = true; + SendThisVC("(pop 1)"); } + + SendThisVC("(push 1)"); + SendThisVC(string.Format("(set-option :{0} {1})", Z3.SetTimeoutOption(), timeLimit)); + popLater = true; + SendThisVC(string.Format("; checking split VC with {0} unverified assertions", unverifiedCount)); var expr = VCExpressionGenerator.True; for (int i = 0; i < split.Length; i++) -- cgit v1.2.3 From acb3bb31dffcdba7f63e9ab041bb83d26f23e7b8 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Wed, 20 May 2015 15:16:45 +0200 Subject: Minor refactoring --- Source/Provers/SMTLib/ProverInterface.cs | 68 +++++++++----------------------- 1 file changed, 19 insertions(+), 49 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index ac804b31..9ec8b6f1 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1268,42 +1268,25 @@ namespace Microsoft.Boogie.SMTLib SendThisVC("; begin timeout diagnostics"); - var verified = new bool[Context.TimoutDiagnosticsCount]; - var lastCnt = verified.Length + 1; + var unverified = new SortedSet(ctx.TimeoutDiagnosticIDToAssertion.Keys); + var lastCnt = unverified.Count + 1; var mod = 2; var timeLimit = options.TimeLimit; var timeLimitFactor = 1; while (true) { - var split0 = verified.ToArray(); - var split1 = verified.ToArray(); - int cnt0 = 0; - int cnt1 = 0; - for (int i = 0; i < split0.Length; i++) - { - if (!split0[i]) - { - // TODO(wuestholz): Try out different ways for splitting up the work. - if ((cnt0 + cnt1) % mod == 0) - { - split0[i] = true; - cnt1++; - } - else - { - split1[i] = true; - cnt0++; - } - } - } + // TODO(wuestholz): Try out different ways for splitting up the work. + var split0 = new SortedSet(unverified.Where((val, idx) => idx % mod == 0)); + var split1 = new SortedSet(unverified.Except(split0)); + + int cnt = unverified.Count; - var cnt = cnt0 + cnt1; if (cnt == 0) { result = Outcome.Valid; break; } - else if (lastCnt <= cnt) + else if (lastCnt == cnt) { if (mod < cnt) { @@ -1317,14 +1300,7 @@ namespace Microsoft.Boogie.SMTLib else { // Give up and report which assertions were not verified. - var cmds = new List>(); - for (int i = 0; i < verified.Length; i++) - { - if (!verified[i]) - { - cmds.Add(ctx.TimeoutDiagnosticIDToAssertion[i]); - } - } + var cmds = unverified.Select(id => ctx.TimeoutDiagnosticIDToAssertion[id]); if (cmds.Any()) { @@ -1336,15 +1312,12 @@ namespace Microsoft.Boogie.SMTLib } lastCnt = cnt; - if (0 < cnt0) + if (0 < split0.Count) { - var result0 = CheckSplit(split0, cnt0, ref popLater, timeLimitFactor * timeLimit); + var result0 = CheckSplit(split0, ref popLater, timeLimitFactor * timeLimit); if (result0 == Outcome.Valid) { - for (int i = 0; i < split0.Length; i++) - { - verified[i] = verified[i] || !split0[i]; - } + unverified.ExceptWith(split0); } else if (result0 == Outcome.Invalid) { @@ -1353,15 +1326,12 @@ namespace Microsoft.Boogie.SMTLib } } - if (0 < cnt1) + if (0 < split1.Count) { - var result1 = CheckSplit(split1, cnt1, ref popLater, timeLimitFactor * timeLimit); + var result1 = CheckSplit(split1, ref popLater, timeLimitFactor * timeLimit); if (result1 == Outcome.Valid) { - for (int i = 0; i < split1.Length; i++) - { - verified[i] = verified[i] || !split1[i]; - } + unverified.ExceptWith(split1); } else if (result1 == Outcome.Invalid) { @@ -1447,7 +1417,7 @@ namespace Microsoft.Boogie.SMTLib } } - private Outcome CheckSplit(bool[] split, int unverifiedCount, ref bool popLater, int timeLimit) + private Outcome CheckSplit(SortedSet split, ref bool popLater, int timeLimit) { if (popLater) { @@ -1458,12 +1428,12 @@ namespace Microsoft.Boogie.SMTLib SendThisVC(string.Format("(set-option :{0} {1})", Z3.SetTimeoutOption(), timeLimit)); popLater = true; - SendThisVC(string.Format("; checking split VC with {0} unverified assertions", unverifiedCount)); + SendThisVC(string.Format("; checking split VC with {0} unverified assertions", split.Count)); var expr = VCExpressionGenerator.True; - for (int i = 0; i < split.Length; i++) + foreach (var i in ctx.TimeoutDiagnosticIDToAssertion.Keys) { var lit = VCExprGen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, VCExprGen.Integer(Microsoft.Basetypes.BigNum.FromInt(i))); - if (!split[i]) { + if (split.Contains(i)) { lit = VCExprGen.Not(lit); } expr = VCExprGen.AndSimp(expr, lit); -- cgit v1.2.3 From 5bcf7c6c005233137cde6f908c6801a911aeca0a Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Wed, 20 May 2015 19:39:24 +0200 Subject: Minor changes --- Source/Houdini/Checker.cs | 1 + Source/Provers/SMTLib/ProverInterface.cs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Source/Houdini/Checker.cs b/Source/Houdini/Checker.cs index 30056d99..d9da29cc 100644 --- a/Source/Houdini/Checker.cs +++ b/Source/Houdini/Checker.cs @@ -238,6 +238,7 @@ namespace Microsoft.Boogie.Houdini { stats.proverTime += queryTime; stats.numProverQueries++; if (CommandLineOptions.Clo.Trace) { + Console.WriteLine("Outcome = " + proverOutcome); Console.WriteLine("Time taken = " + queryTime); } diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index 9ec8b6f1..594f2509 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1310,6 +1310,10 @@ namespace Microsoft.Boogie.SMTLib break; } } + else + { + mod = 2; + } lastCnt = cnt; if (0 < split0.Count) @@ -1439,6 +1443,10 @@ namespace Microsoft.Boogie.SMTLib expr = VCExprGen.AndSimp(expr, lit); } SendThisVC("(assert " + VCExpr2String(expr, 1) + ")"); + if (options.Solver == SolverKind.Z3) + { + SendThisVC("(apply (then (using-params propagate-values :max_rounds 1) simplify) :print false)"); + } FlushLogFile(); SendThisVC("(check-sat)"); return GetResponse(); -- cgit v1.2.3 From 69f00af6f384f422d0ccafece7cffc98dc5cbefa Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 20 May 2015 12:16:36 -0700 Subject: added more specifications --- Test/civl/Program5.bpl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Test/civl/Program5.bpl b/Test/civl/Program5.bpl index 7ede3124..d728b845 100644 --- a/Test/civl/Program5.bpl +++ b/Test/civl/Program5.bpl @@ -22,20 +22,24 @@ ensures {:layer 2} Color >= old(Color); procedure {:yields} {:layer 2,3} WriteBarrier({:linear "tid"} tid:Tid) ensures {:atomic} |{ A: assert tid != nil; goto B, C; B: assume White(Color); Color := GRAY(); return true; - C: return true;}|; + C: assume !White(Color); return true;}|; +requires {:layer 2} Color >= WHITE(); +ensures {:layer 2} Color >= GRAY(); { var colorLocal:int; yield; + assert {:layer 2} Color >= WHITE(); call colorLocal := GetColorNoLock(); call YieldColorOnlyGetsDarker(); if (White(colorLocal)) { call WriteBarrierSlow(tid); } yield; + assert {:layer 2} Color >= GRAY(); } procedure {:yields} {:layer 1,2} WriteBarrierSlow({:linear "tid"} tid:Tid) ensures {:atomic} |{ A: assert tid != nil; goto B, C; B: assume White(Color); Color := GRAY(); return true; - C: return true; }|; + C: assume !White(Color); return true; }|; { var colorLocal:int; yield; -- cgit v1.2.3 From 846dd8fd2c345e20e3d85d4a07d73ddfab5ac45c Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 22 May 2015 13:43:51 +0200 Subject: Improve support for diagnosing timeouts. --- Source/Provers/SMTLib/ProverInterface.cs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index 594f2509..e09eabcb 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1269,28 +1269,24 @@ namespace Microsoft.Boogie.SMTLib SendThisVC("; begin timeout diagnostics"); var unverified = new SortedSet(ctx.TimeoutDiagnosticIDToAssertion.Keys); - var lastCnt = unverified.Count + 1; - var mod = 2; + var lastCnt = 0; var timeLimit = options.TimeLimit; var timeLimitFactor = 1; + var frac = 2; while (true) { - // TODO(wuestholz): Try out different ways for splitting up the work. - var split0 = new SortedSet(unverified.Where((val, idx) => idx % mod == 0)); - var split1 = new SortedSet(unverified.Except(split0)); - int cnt = unverified.Count; - if (cnt == 0) { result = Outcome.Valid; break; } - else if (lastCnt == cnt) + + if (lastCnt == cnt) { - if (mod < cnt) + if ((2 * frac) < cnt) { - mod++; + frac *= 2; } else if (timeLimitFactor <= 3 && 0 < timeLimit) { @@ -1312,13 +1308,19 @@ namespace Microsoft.Boogie.SMTLib } else { - mod = 2; + frac = 2; } lastCnt = cnt; + // TODO(wuestholz): Try out different ways for splitting up the work (e.g., randomly). + var cnt0 = cnt / frac; + var split0 = new SortedSet(unverified.Where((val, idx) => idx < cnt0)); + var split1 = new SortedSet(unverified.Except(split0)); + if (0 < split0.Count) { - var result0 = CheckSplit(split0, ref popLater, timeLimitFactor * timeLimit); + var stl = 0 < timeLimit ? split0.Count * ((timeLimit / cnt) + 1) : timeLimit; + var result0 = CheckSplit(split0, ref popLater, timeLimitFactor * stl); if (result0 == Outcome.Valid) { unverified.ExceptWith(split0); @@ -1332,7 +1334,8 @@ namespace Microsoft.Boogie.SMTLib if (0 < split1.Count) { - var result1 = CheckSplit(split1, ref popLater, timeLimitFactor * timeLimit); + var stl = 0 < timeLimit ? split1.Count * ((timeLimit / cnt) + 1) : timeLimit; + var result1 = CheckSplit(split1, ref popLater, timeLimitFactor * stl); if (result1 == Outcome.Valid) { unverified.ExceptWith(split1); -- cgit v1.2.3 From 7971dd771c21090edf5d9bc8a3c3766daed529e0 Mon Sep 17 00:00:00 2001 From: Akash Lal Date: Mon, 25 May 2015 18:24:58 +0530 Subject: Allow for extra instrumentation on program before vc gen --- Source/VCGeneration/StratifiedVC.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index 69b7c8cc..43b5f88a 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -365,13 +365,16 @@ namespace VC { public Dictionary> callSites; public Dictionary> recordProcCallSites; public bool initialized { get; private set; } + // Instrumentation to apply after PassiveImpl, but before VCGen + Action PassiveImplInstrumentation; // boolControlVC (block -> its Bool variable) public Dictionary blockToControlVar; - public StratifiedInliningInfo(Implementation implementation, StratifiedVCGenBase stratifiedVcGen) { + public StratifiedInliningInfo(Implementation implementation, StratifiedVCGenBase stratifiedVcGen, Action PassiveImplInstrumentation) { vcgen = stratifiedVcGen; impl = implementation; + this.PassiveImplInstrumentation = PassiveImplInstrumentation; List functionInterfaceVars = new List(); foreach (Variable v in vcgen.program.GlobalVariables) { @@ -581,6 +584,9 @@ namespace VC { vcgen.ConvertCFG2DAG(impl); vcgen.PassifyImpl(impl, out mvInfo); + if (PassiveImplInstrumentation != null) + PassiveImplInstrumentation(impl); + VCExpressionGenerator gen = proverInterface.VCExprGen; var exprGen = proverInterface.Context.ExprGen; var translator = proverInterface.Context.BoogieExprTranslator; @@ -636,12 +642,12 @@ namespace VC { public Dictionary implName2StratifiedInliningInfo; public ProverInterface prover; - public StratifiedVCGenBase(Program program, string/*?*/ logFilePath, bool appendLogFile, List checkers) + public StratifiedVCGenBase(Program program, string/*?*/ logFilePath, bool appendLogFile, List checkers, Action PassiveImplInstrumentation) : base(program, logFilePath, appendLogFile, checkers) { implName2StratifiedInliningInfo = new Dictionary(); prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime); foreach (var impl in program.Implementations) { - implName2StratifiedInliningInfo[impl.Name] = new StratifiedInliningInfo(impl, this); + implName2StratifiedInliningInfo[impl.Name] = new StratifiedInliningInfo(impl, this, PassiveImplInstrumentation); } GenerateRecordFunctions(); } @@ -847,7 +853,7 @@ namespace VC { } public StratifiedVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List checkers) - : base(program, logFilePath, appendLogFile, checkers) { + : base(program, logFilePath, appendLogFile, checkers, null) { PersistCallTree = false; procsThatReachedRecBound = new HashSet(); procsToSkip = new HashSet(); -- cgit v1.2.3 From 7e286186df1932c299c1acb3a62310d4bfd36172 Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 27 May 2015 16:05:37 -0700 Subject: bug fix in pop --- Test/civl/treiber-stack.bpl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Test/civl/treiber-stack.bpl b/Test/civl/treiber-stack.bpl index e1c509ab..286c7dd1 100644 --- a/Test/civl/treiber-stack.bpl +++ b/Test/civl/treiber-stack.bpl @@ -82,15 +82,13 @@ ensures {:atomic} |{ A: Stack := Add(Stack, x, TopOfStack); TopOfStack := x; ret assert {:expand} {:layer 1} Inv(TopOfStack, Stack); } -procedure {:yields} {:layer 1} pop() +procedure {:yields} {:layer 1} pop() returns (t: Node) requires {:layer 1} Inv(TopOfStack, Stack); ensures {:layer 1} Inv(TopOfStack, Stack); -ensures {:atomic} |{ var t: Node; - A: assume TopOfStack != null; t := TopOfStack; Used := Add(Used, t, map(Stack)[t]); TopOfStack := map(Stack)[t]; Stack := Remove(Stack, t); return true; }|; +ensures {:atomic} |{ A: assume TopOfStack != null; t := TopOfStack; Used := Add(Used, t, map(Stack)[t]); TopOfStack := map(Stack)[t]; Stack := Remove(Stack, t); return true; }|; { var g: bool; var x: Node; - var t: Node; yield; assert {:layer 1} Inv(TopOfStack, Stack); -- cgit v1.2.3 From 39e35e01bb03719568598162d7f2142fb87ea4fe Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Sun, 31 May 2015 12:18:43 +0200 Subject: Improve heuristics for diagnosing timeouts. --- Source/Provers/SMTLib/ProverInterface.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index e09eabcb..c257ea14 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1284,14 +1284,14 @@ namespace Microsoft.Boogie.SMTLib if (lastCnt == cnt) { - if ((2 * frac) < cnt) + if (frac < (cnt / 2)) { frac *= 2; } - else if (timeLimitFactor <= 3 && 0 < timeLimit) + else if (0 < timeLimit && timeLimitFactor <= 4) { // TODO(wuestholz): Add a commandline option to control this. - timeLimitFactor++; + timeLimitFactor *= 2; } else { @@ -1309,6 +1309,7 @@ namespace Microsoft.Boogie.SMTLib else { frac = 2; + timeLimitFactor = 1; } lastCnt = cnt; @@ -1319,8 +1320,7 @@ namespace Microsoft.Boogie.SMTLib if (0 < split0.Count) { - var stl = 0 < timeLimit ? split0.Count * ((timeLimit / cnt) + 1) : timeLimit; - var result0 = CheckSplit(split0, ref popLater, timeLimitFactor * stl); + var result0 = CheckSplit(split0, ref popLater, timeLimitFactor * timeLimit); if (result0 == Outcome.Valid) { unverified.ExceptWith(split0); @@ -1334,7 +1334,7 @@ namespace Microsoft.Boogie.SMTLib if (0 < split1.Count) { - var stl = 0 < timeLimit ? split1.Count * ((timeLimit / cnt) + 1) : timeLimit; + var stl = 0 < timeLimit ? (frac - 1) * timeLimit : timeLimit; var result1 = CheckSplit(split1, ref popLater, timeLimitFactor * stl); if (result1 == Outcome.Valid) { -- cgit v1.2.3 From ac44a0e0ba8679be11ce0759ec58e3891a1ad318 Mon Sep 17 00:00:00 2001 From: qadeer Date: Sun, 31 May 2015 14:05:58 -0700 Subject: added assume about gate after calls and parallel calls --- Source/Concurrency/OwickiGries.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Source/Concurrency/OwickiGries.cs b/Source/Concurrency/OwickiGries.cs index dbd1dcbd..626f2c4a 100644 --- a/Source/Concurrency/OwickiGries.cs +++ b/Source/Concurrency/OwickiGries.cs @@ -919,6 +919,15 @@ namespace Microsoft.Boogie { HashSet availableLinearVars = new HashSet(AvailableLinearVars(callCmd)); linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); + + if (!callCmd.IsAsync && globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } @@ -930,6 +939,15 @@ namespace Microsoft.Boogie DesugarParallelCallCmd(newCmds, parCallCmd); HashSet availableLinearVars = new HashSet(AvailableLinearVars(parCallCmd)); linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); + + if (globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } -- cgit v1.2.3 From dfaac23736f142a4c66a8457f7a4be99b245cb98 Mon Sep 17 00:00:00 2001 From: akashlal Date: Mon, 1 Jun 2015 10:38:33 +0530 Subject: Simplified StratifiedVC interface --- Source/VCGeneration/StratifiedVC.cs | 40 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index 43b5f88a..da2c37c6 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -832,17 +832,20 @@ namespace VC { public int numInlined = 0; public int vcsize = 0; private HashSet procsThatReachedRecBound; - public HashSet procsToSkip; - public Dictionary extraRecBound; + private Dictionary extraRecBound; public StratifiedVCGen(bool usePrevCallTree, HashSet prevCallTree, - HashSet procsToSkip, Dictionary extraRecBound, Program program, string/*?*/ logFilePath, bool appendLogFile, List checkers) : this(program, logFilePath, appendLogFile, checkers) { - this.procsToSkip = new HashSet(procsToSkip); - this.extraRecBound = new Dictionary(extraRecBound); - + this.extraRecBound = new Dictionary(); + program.TopLevelDeclarations.OfType() + .Iter(impl => + { + var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1); + if(b != -1) extraRecBound.Add(impl.Name, b); + }); + if (usePrevCallTree) { callTree = prevCallTree; PersistCallTree = true; @@ -856,18 +859,8 @@ namespace VC { : base(program, logFilePath, appendLogFile, checkers, null) { PersistCallTree = false; procsThatReachedRecBound = new HashSet(); - procsToSkip = new HashSet(); - extraRecBound = new Dictionary(); } - // Is this procedure to be "skipped" - // Currently this is experimental - public bool isSkipped(string procName) { - return procsToSkip.Contains(procName); - } - public bool isSkipped(int candidate, FCallHandler calls) { - return isSkipped(calls.getProc(candidate)); - } // Extra rec bound for procedures public int GetExtraRecBound(string procName) { if (!extraRecBound.ContainsKey(procName)) @@ -1321,16 +1314,9 @@ namespace VC { Console.Write(">> SI Inlining: "); reporter.candidatesToExpand .Select(c => calls.getProc(c)) - .Iter(c => { if (!isSkipped(c)) Console.Write("{0} ", c); }); + .Iter(c => Console.Write("{0} ", c)); Console.WriteLine(); - Console.Write(">> SI Skipping: "); - reporter.candidatesToExpand - .Select(c => calls.getProc(c)) - .Iter(c => { if (isSkipped(c)) Console.Write("{0} ", c); }); - - Console.WriteLine(); - } // Expand and try again @@ -1349,7 +1335,6 @@ namespace VC { if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) { Console.WriteLine(">> SI: Expansions performed: {0}", vState.expansionCount); Console.WriteLine(">> SI: Candidates left: {0}", calls.currCandidates.Count); - Console.WriteLine(">> SI: Candidates skipped: {0}", calls.currCandidates.Where(i => isSkipped(i, calls)).Count()); Console.WriteLine(">> SI: VC Size: {0}", vState.vcSize); } @@ -1390,7 +1375,6 @@ namespace VC { List assumptions = new List(); foreach (int id in calls.currCandidates) { - if (!isSkipped(id, calls)) assumptions.Add(calls.getFalseExpr(id)); } Outcome ret = checker.CheckAssumptions(assumptions); @@ -1424,7 +1408,6 @@ namespace VC { procsThatReachedRecBound.Clear(); foreach (int id in calls.currCandidates) { - if (isSkipped(id, calls)) continue; int idBound = calls.getRecursionBound(id); int sd = calls.getStackDepth(id); @@ -1491,9 +1474,6 @@ namespace VC { Contract.Requires(vState.checker.prover != null); Contract.EnsuresOnThrow(true); - // Skipped calls don't get inlined - candidates = candidates.FindAll(id => !isSkipped(id, vState.calls)); - vState.expansionCount += candidates.Count; var prover = vState.checker.prover; -- cgit v1.2.3 From b42d69a32e0e3a8132fd4b1288618fe4a7392eb6 Mon Sep 17 00:00:00 2001 From: Akash Lal Date: Fri, 5 Jun 2015 10:09:41 +0530 Subject: Fix for SI: initialize extraRecBound --- Source/VCGeneration/StratifiedVC.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index da2c37c6..037fa2be 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -837,15 +837,7 @@ namespace VC { public StratifiedVCGen(bool usePrevCallTree, HashSet prevCallTree, Program program, string/*?*/ logFilePath, bool appendLogFile, List checkers) : this(program, logFilePath, appendLogFile, checkers) - { - this.extraRecBound = new Dictionary(); - program.TopLevelDeclarations.OfType() - .Iter(impl => - { - var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1); - if(b != -1) extraRecBound.Add(impl.Name, b); - }); - + { if (usePrevCallTree) { callTree = prevCallTree; PersistCallTree = true; @@ -859,6 +851,14 @@ namespace VC { : base(program, logFilePath, appendLogFile, checkers, null) { PersistCallTree = false; procsThatReachedRecBound = new HashSet(); + + extraRecBound = new Dictionary(); + program.TopLevelDeclarations.OfType() + .Iter(impl => + { + var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1); + if (b != -1) extraRecBound.Add(impl.Name, b); + }); } // Extra rec bound for procedures -- cgit v1.2.3 From 82bf08e30124735b41ea901530ce40ef4944c9c9 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 5 Jun 2015 12:09:49 +0200 Subject: Improve support for diagnosing timeouts. --- Source/Core/CommandLineOptions.cs | 7 ++++++ Source/ExecutionEngine/ExecutionEngine.cs | 2 +- Source/Provers/SMTLib/ProverInterface.cs | 37 ++++++++++++++++++++++++++---- Source/VCGeneration/Check.cs | 3 ++- Source/VCGeneration/ConditionGeneration.cs | 11 ++++++--- 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index 03545cbf..b9684d04 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -558,6 +558,8 @@ namespace Microsoft.Boogie { public bool WeakArrayTheory = false; public bool UseLabels = true; public bool RunDiagnosticsOnTimeout = false; + public bool TraceDiagnosticsOnTimeout = false; + public int TimeLimitPerAssertionInMs = -1; public bool SIBoolControlVC = false; public bool MonomorphicArrays { get { @@ -1477,6 +1479,10 @@ namespace Microsoft.Boogie { ps.GetNumericArgument(ref ProverKillTime); return true; + case "timeLimitPerAssertionInMs": + ps.GetNumericArgument(ref TimeLimitPerAssertionInMs); + return true; + case "smokeTimeout": ps.GetNumericArgument(ref SmokeTimeout); return true; @@ -1587,6 +1593,7 @@ namespace Microsoft.Boogie { ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) || ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false) || ps.CheckBooleanFlag("runDiagnosticsOnTimeout", ref RunDiagnosticsOnTimeout) || + ps.CheckBooleanFlag("traceDiagnosticsOnTimeout", ref RunDiagnosticsOnTimeout) || ps.CheckBooleanFlag("boolControlVC", ref SIBoolControlVC, true) || ps.CheckBooleanFlag("contractInfer", ref ContractInfer) || ps.CheckBooleanFlag("explainHoudini", ref ExplainHoudini) || diff --git a/Source/ExecutionEngine/ExecutionEngine.cs b/Source/ExecutionEngine/ExecutionEngine.cs index 31a69c6e..67ce49a5 100644 --- a/Source/ExecutionEngine/ExecutionEngine.cs +++ b/Source/ExecutionEngine/ExecutionEngine.cs @@ -968,7 +968,7 @@ namespace Microsoft.Boogie { semaphore.Release(); } - }, cts.Token, TaskCreationOptions.LongRunning); + }, cts.Token, TaskCreationOptions.None); tasks[taskIndex] = t; } diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index c257ea14..e9cb9a08 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -454,7 +454,7 @@ namespace Microsoft.Boogie.SMTLib ctx.KnownDatatypeConstructors.Clear(); ctx.parent = this; DeclCollector.Reset(); - SendThisVC("; doing a full reset..."); + SendThisVC("; did a full reset"); } } @@ -1266,11 +1266,19 @@ namespace Microsoft.Boogie.SMTLib { #region Run timeout diagnostics + if (CommandLineOptions.Clo.TraceDiagnosticsOnTimeout) + { + Console.Out.WriteLine("Starting timeout diagnostics with initial time limit {0}.", options.TimeLimit); + } + + var start = DateTime.UtcNow; + SendThisVC("; begin timeout diagnostics"); var unverified = new SortedSet(ctx.TimeoutDiagnosticIDToAssertion.Keys); var lastCnt = 0; var timeLimit = options.TimeLimit; + var timeLimitPerAssertion = CommandLineOptions.Clo.TimeLimitPerAssertionInMs; var timeLimitFactor = 1; var frac = 2; while (true) @@ -1320,7 +1328,9 @@ namespace Microsoft.Boogie.SMTLib if (0 < split0.Count) { - var result0 = CheckSplit(split0, ref popLater, timeLimitFactor * timeLimit); + var tl = timeLimitFactor * timeLimit; + var tla = timeLimitPerAssertion * split0.Count; + var result0 = CheckSplit(split0, ref popLater, (0 < tla && tla < tl) ? tla : tl); if (result0 == Outcome.Valid) { unverified.ExceptWith(split0); @@ -1334,8 +1344,10 @@ namespace Microsoft.Boogie.SMTLib if (0 < split1.Count) { - var stl = 0 < timeLimit ? (frac - 1) * timeLimit : timeLimit; - var result1 = CheckSplit(split1, ref popLater, timeLimitFactor * stl); + var tl = 0 < timeLimit ? (frac - 1) * timeLimit : timeLimit; + tl = timeLimitFactor * tl; + var tla = timeLimitPerAssertion * split1.Count; + var result1 = CheckSplit(split1, ref popLater, (0 < tla && tla < tl) ? tla : tl); if (result1 == Outcome.Valid) { unverified.ExceptWith(split1); @@ -1350,6 +1362,23 @@ namespace Microsoft.Boogie.SMTLib SendThisVC("; end timeout diagnostics"); + var end = DateTime.UtcNow; + + if (CommandLineOptions.Clo.TraceDiagnosticsOnTimeout) + { + Console.Out.WriteLine("Terminated timeout diagnostics after {0:F0} ms.", end.Subtract(start).TotalMilliseconds); + Console.Out.WriteLine("Outcome: {0}", result); + Console.Out.WriteLine("Unverified assertions: {0} (of {1})", unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count); + + string filename = "unknown"; + var assertion = ctx.TimeoutDiagnosticIDToAssertion.Values.Select(t => t.Item1).FirstOrDefault(a => a.tok != null && a.tok != Token.NoToken && a.tok.filename != null); + if (assertion != null) + { + filename = assertion.tok.filename; + } + File.AppendAllText("timeouts.csv", string.Format(";{0};{1};{2:F0};{3};{4};{5}\n", filename, options.TimeLimit, end.Subtract(start).TotalMilliseconds, result, unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count)); + } + #endregion } diff --git a/Source/VCGeneration/Check.cs b/Source/VCGeneration/Check.cs index 7c690eff..33baf798 100644 --- a/Source/VCGeneration/Check.cs +++ b/Source/VCGeneration/Check.cs @@ -217,6 +217,7 @@ namespace Microsoft.Boogie { private void Setup(Program prog, ProverContext ctx) { Program = prog; + // TODO(wuestholz): Is this lock necessary? lock (Program.TopLevelDeclarations) { foreach (Declaration decl in Program.TopLevelDeclarations) @@ -362,7 +363,7 @@ namespace Microsoft.Boogie { thmProver.BeginCheck(descriptiveName, vc, handler); // gen.ClearSharedFormulas(); PR: don't know yet what to do with this guy - ProverTask = Task.Factory.StartNew(() => { WaitForOutput(null); } , TaskCreationOptions.LongRunning); + ProverTask = Task.Factory.StartNew(() => { WaitForOutput(null); }, TaskCreationOptions.LongRunning); } public ProverInterface.Outcome ReadOutcome() { diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs index a19f983a..8d6606b6 100644 --- a/Source/VCGeneration/ConditionGeneration.cs +++ b/Source/VCGeneration/ConditionGeneration.cs @@ -983,11 +983,11 @@ namespace VC { #endregion - protected Checker FindCheckerFor(int timeout, bool isBlocking = true) + protected Checker FindCheckerFor(int timeout, bool isBlocking = true, int waitTimeinMs = 50, int maxRetries = 3) { + Contract.Requires(0 <= waitTimeinMs && 0 <= maxRetries); Contract.Ensures(!isBlocking || Contract.Result() != null); - var maxRetries = 3; lock (checkers) { retry: @@ -1015,6 +1015,8 @@ namespace VC { else { checkers.RemoveAt(i); + i--; + continue; } } } @@ -1029,7 +1031,10 @@ namespace VC { { if (isBlocking || 0 < maxRetries) { - Monitor.Wait(checkers, 50); + if (0 < waitTimeinMs) + { + Monitor.Wait(checkers, waitTimeinMs); + } maxRetries--; goto retry; } -- cgit v1.2.3 From 5d509aecf42406ad94a76aac49342a37620fb829 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 5 Jun 2015 23:25:22 +0200 Subject: Fix minor issue. --- Source/Core/CommandLineOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index b9684d04..675ac6a5 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -1593,7 +1593,7 @@ namespace Microsoft.Boogie { ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) || ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false) || ps.CheckBooleanFlag("runDiagnosticsOnTimeout", ref RunDiagnosticsOnTimeout) || - ps.CheckBooleanFlag("traceDiagnosticsOnTimeout", ref RunDiagnosticsOnTimeout) || + ps.CheckBooleanFlag("traceDiagnosticsOnTimeout", ref TraceDiagnosticsOnTimeout) || ps.CheckBooleanFlag("boolControlVC", ref SIBoolControlVC, true) || ps.CheckBooleanFlag("contractInfer", ref ContractInfer) || ps.CheckBooleanFlag("explainHoudini", ref ExplainHoudini) || -- cgit v1.2.3 From 8f64d5c104efe69c5d561c1b22c3e1320bba04fa Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Mon, 8 Jun 2015 00:15:01 +0200 Subject: Improve support for diagnosing timeouts. --- Source/Core/CommandLineOptions.cs | 6 +- Source/Provers/SMTLib/ProverInterface.cs | 131 ++++++++++++++----------------- 2 files changed, 64 insertions(+), 73 deletions(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index 675ac6a5..be371fcb 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -559,7 +559,7 @@ namespace Microsoft.Boogie { public bool UseLabels = true; public bool RunDiagnosticsOnTimeout = false; public bool TraceDiagnosticsOnTimeout = false; - public int TimeLimitPerAssertionInMs = -1; + public int TimeLimitPerAssertionInPercent = 20; public bool SIBoolControlVC = false; public bool MonomorphicArrays { get { @@ -1479,8 +1479,8 @@ namespace Microsoft.Boogie { ps.GetNumericArgument(ref ProverKillTime); return true; - case "timeLimitPerAssertionInMs": - ps.GetNumericArgument(ref TimeLimitPerAssertionInMs); + case "timeLimitPerAssertionInPercent": + ps.GetNumericArgument(ref TimeLimitPerAssertionInPercent, a => 0 < a); return true; case "smokeTimeout": diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index e9cb9a08..afb38986 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1271,102 +1271,90 @@ namespace Microsoft.Boogie.SMTLib Console.Out.WriteLine("Starting timeout diagnostics with initial time limit {0}.", options.TimeLimit); } - var start = DateTime.UtcNow; - SendThisVC("; begin timeout diagnostics"); + var start = DateTime.UtcNow; var unverified = new SortedSet(ctx.TimeoutDiagnosticIDToAssertion.Keys); - var lastCnt = 0; - var timeLimit = options.TimeLimit; - var timeLimitPerAssertion = CommandLineOptions.Clo.TimeLimitPerAssertionInMs; - var timeLimitFactor = 1; - var frac = 2; + var timedOut = new SortedSet(); + int frac = 2; + int queries = 0; + int timeLimitPerAssertion = 0 < options.TimeLimit ? (options.TimeLimit / 100) * CommandLineOptions.Clo.TimeLimitPerAssertionInPercent : 1000; while (true) { - int cnt = unverified.Count; - if (cnt == 0) + int rem = unverified.Count; + if (rem == 0) { - result = Outcome.Valid; - break; - } - - if (lastCnt == cnt) - { - if (frac < (cnt / 2)) + if (0 < timedOut.Count) { - frac *= 2; - } - else if (0 < timeLimit && timeLimitFactor <= 4) - { - // TODO(wuestholz): Add a commandline option to control this. - timeLimitFactor *= 2; - } - else - { - // Give up and report which assertions were not verified. - var cmds = unverified.Select(id => ctx.TimeoutDiagnosticIDToAssertion[id]); - - if (cmds.Any()) + result = CheckSplit(timedOut, ref popLater, options.TimeLimit, timeLimitPerAssertion, ref queries); + if (result == Outcome.Valid) { - handler.OnResourceExceeded("timeout after running diagnostics", cmds); + timedOut.Clear(); } + else if (result == Outcome.TimeOut) + { + // Give up and report which assertions were not verified. + var cmds = timedOut.Select(id => ctx.TimeoutDiagnosticIDToAssertion[id]); - break; + if (cmds.Any()) + { + handler.OnResourceExceeded("timeout after running diagnostics", cmds); + } + } } + else + { + result = Outcome.Valid; + } + break; } - else - { - frac = 2; - timeLimitFactor = 1; - } - lastCnt = cnt; // TODO(wuestholz): Try out different ways for splitting up the work (e.g., randomly). - var cnt0 = cnt / frac; - var split0 = new SortedSet(unverified.Where((val, idx) => idx < cnt0)); - var split1 = new SortedSet(unverified.Except(split0)); - - if (0 < split0.Count) + var split = new SortedSet(unverified.Where((val, idx) => idx < ((rem - 1) / frac + 1))); + Contract.Assert(0 < split.Count); + var splitRes = CheckSplit(split, ref popLater, timeLimitPerAssertion, timeLimitPerAssertion, ref queries); + if (splitRes == Outcome.Valid) { - var tl = timeLimitFactor * timeLimit; - var tla = timeLimitPerAssertion * split0.Count; - var result0 = CheckSplit(split0, ref popLater, (0 < tla && tla < tl) ? tla : tl); - if (result0 == Outcome.Valid) - { - unverified.ExceptWith(split0); - } - else if (result0 == Outcome.Invalid) - { - result = result0; - break; - } + unverified.ExceptWith(split); + frac = 1; } - - if (0 < split1.Count) + else if (splitRes == Outcome.Invalid) + { + result = splitRes; + break; + } + else if (splitRes == Outcome.TimeOut) { - var tl = 0 < timeLimit ? (frac - 1) * timeLimit : timeLimit; - tl = timeLimitFactor * tl; - var tla = timeLimitPerAssertion * split1.Count; - var result1 = CheckSplit(split1, ref popLater, (0 < tla && tla < tl) ? tla : tl); - if (result1 == Outcome.Valid) + if (1 < frac && frac <= (rem / 4)) { - unverified.ExceptWith(split1); + frac *= 4; } - else if (result1 == Outcome.Invalid) + else if (frac <= (rem / 2)) { - result = result1; - break; + frac *= 2; + } + else + { + timedOut.UnionWith(split); + unverified.ExceptWith(split); + frac = 1; } } + else + { + break; + } } - SendThisVC("; end timeout diagnostics"); + unverified.UnionWith(timedOut); var end = DateTime.UtcNow; + SendThisVC("; end timeout diagnostics"); + if (CommandLineOptions.Clo.TraceDiagnosticsOnTimeout) { - Console.Out.WriteLine("Terminated timeout diagnostics after {0:F0} ms.", end.Subtract(start).TotalMilliseconds); + Console.Out.WriteLine("Terminated timeout diagnostics after {0:F0} ms and {1} prover queries.", end.Subtract(start).TotalMilliseconds, queries); Console.Out.WriteLine("Outcome: {0}", result); Console.Out.WriteLine("Unverified assertions: {0} (of {1})", unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count); @@ -1376,7 +1364,7 @@ namespace Microsoft.Boogie.SMTLib { filename = assertion.tok.filename; } - File.AppendAllText("timeouts.csv", string.Format(";{0};{1};{2:F0};{3};{4};{5}\n", filename, options.TimeLimit, end.Subtract(start).TotalMilliseconds, result, unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count)); + File.AppendAllText("timeouts.csv", string.Format(";{0};{1};{2:F0};{3};{4};{5};{6}\n", filename, options.TimeLimit, end.Subtract(start).TotalMilliseconds, queries, result, unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count)); } #endregion @@ -1453,15 +1441,17 @@ namespace Microsoft.Boogie.SMTLib } } - private Outcome CheckSplit(SortedSet split, ref bool popLater, int timeLimit) + private Outcome CheckSplit(SortedSet split, ref bool popLater, int timeLimit, int timeLimitPerAssertion, ref int queries) { + var tla = timeLimitPerAssertion * split.Count; + if (popLater) { SendThisVC("(pop 1)"); } SendThisVC("(push 1)"); - SendThisVC(string.Format("(set-option :{0} {1})", Z3.SetTimeoutOption(), timeLimit)); + SendThisVC(string.Format("(set-option :{0} {1})", Z3.SetTimeoutOption(), (0 < tla && tla < timeLimit) ? tla : timeLimit)); popLater = true; SendThisVC(string.Format("; checking split VC with {0} unverified assertions", split.Count)); @@ -1481,6 +1471,7 @@ namespace Microsoft.Boogie.SMTLib } FlushLogFile(); SendThisVC("(check-sat)"); + queries++; return GetResponse(); } -- cgit v1.2.3 From 938bfd15dbd13b2d8eaf5f6a0cb5b895173ffa09 Mon Sep 17 00:00:00 2001 From: Clément Pit--Claudel Date: Tue, 9 Jun 2015 01:03:32 -0700 Subject: Stop truncating the prover logs As it stands, Boogie abruptly aborts the prover by calling Kill() on the associated process after receiving responses to all of its queries. In most cases this is fine, but in general this is pretty bad: it yields to all sorts of output corruption when user-supplied options require z3 to write output to an auxiliary file (say, using /z3opt:TRACE=true). This explains why VCC's Axiom Profiler often complains about a missing [eof] after running Boogie with /z3opt:TRACE=true. This patch fixes it by only falling back to Kill if the process seems to have become unresponsive. That is, it starts by cleanly closing the process input, which signals the end of the interactive session. It then waits for a clean exit for 2s, and only after that does it resort to calling Kill(). I've striven for minimal modifications to the logic, so the patch still universally swallows errors that might occur while closing the underlying stream, and still calls Kill() (I wouldn't be against Boogie just hanging if z3 hangs too). On my tests, z3 exits cleanly pretty much instantly after input is closed anyway, so I don't expect the timeout to fire often (which would be one more reason to actually remove that timeout, and condition Boogie's exit on that of z3 IMO). --- Source/Provers/SMTLib/SMTLibProcess.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs index 4a1331c5..7776f4de 100644 --- a/Source/Provers/SMTLib/SMTLibProcess.cs +++ b/Source/Provers/SMTLib/SMTLibProcess.cs @@ -80,10 +80,22 @@ namespace Microsoft.Boogie.SMTLib void ControlCHandler(object o, ConsoleCancelEventArgs a) { if (prover != null) { - prover.Kill(); + TerminateProver(); } } + private void TerminateProver(Int32 timeout = 2000) { + try { + // Let the prover know that we're done sending input. + prover.StandardInput.Close(); + + // Give it a chance to exit cleanly (e.g. to flush buffers) + if (!prover.WaitForExit(timeout)) { + prover.Kill(); + } + } catch { /* Swallow errors */ } + } + public void Send(string cmd) { if (options.Verbosity >= 2) { @@ -180,10 +192,7 @@ namespace Microsoft.Boogie.SMTLib public void Close() { TotalUserTime += prover.UserProcessorTime; - try { - prover.Kill(); - } catch { - } + TerminateProver(); DisposeProver(); } -- cgit v1.2.3 From 073ddcc74e239cb9b270cc2e6db60e1daa033518 Mon Sep 17 00:00:00 2001 From: "U-REDMOND\\kenmcmil" Date: Tue, 9 Jun 2015 15:51:05 -0700 Subject: various changes for duality from dead codeplex repo --- Source/Core/CommandLineOptions.cs | 11 ++++++- Source/Provers/SMTLib/ProverInterface.cs | 9 ++++- Source/Provers/SMTLib/Z3.cs | 3 +- Source/VCGeneration/Check.cs | 3 +- Source/VCGeneration/FixedpointVC.cs | 56 +++++++++++++++++++------------- 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index be371fcb..1564b76b 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -418,6 +418,8 @@ namespace Microsoft.Boogie { public string SimplifyLogFilePath = null; public bool PrintInstrumented = false; public bool InstrumentWithAsserts = false; + public string ProverPreamble = null; + public enum InstrumentationPlaces { LoopHeaders, Everywhere @@ -938,7 +940,14 @@ namespace Microsoft.Boogie { } return true; - case "logPrefix": + case "proverPreamble": + if (ps.ConfirmArgumentCount(1)) + { + ProverPreamble = args[ps.i]; + } + return true; + + case "logPrefix": if (ps.ConfirmArgumentCount(1)) { string s = cce.NonNull(args[ps.i]); LogPrefix += s.Replace('/', '-').Replace('\\', '-'); diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index afb38986..c6c04b89 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -321,6 +321,8 @@ namespace Microsoft.Boogie.SMTLib SendCommon("(declare-datatypes () (" + datatypeString + "))"); } } + if (CommandLineOptions.Clo.ProverPreamble != null) + SendCommon("(include \"" + CommandLineOptions.Clo.ProverPreamble + "\")"); } if (!AxiomsAreSetup) @@ -1016,6 +1018,9 @@ namespace Microsoft.Boogie.SMTLib case "unknown": result = Outcome.Invalid; break; + case "bounded": + result = Outcome.Bounded; + break; case "error": if (resp.ArgCount > 0 && resp.Arguments[0].Name.Contains("canceled")) { @@ -1053,7 +1058,8 @@ namespace Microsoft.Boogie.SMTLib HandleProverError("Unexpected prover response: " + resp.ToString()); break; } - case Outcome.Valid: + case Outcome.Valid: + case Outcome.Bounded: { resp = Process.GetProverResponse(); if (resp.Name == "fixedpoint") @@ -1170,6 +1176,7 @@ namespace Microsoft.Boogie.SMTLib usedLogNames.Add(curFilename); } + Console.WriteLine("opening log file {0}", curFilename); return new StreamWriter(curFilename, false); } diff --git a/Source/Provers/SMTLib/Z3.cs b/Source/Provers/SMTLib/Z3.cs index 250e04c9..ffa4e0cb 100644 --- a/Source/Provers/SMTLib/Z3.cs +++ b/Source/Provers/SMTLib/Z3.cs @@ -248,7 +248,8 @@ namespace Microsoft.Boogie.SMTLib // Complex proof attempts in VCC (and likely elsewhere) require matching depth of 20 or more. // the following will make the :weight option more usable - if (!fp) options.AddWeakSmtOption("smt.QI.COST", "|(+ weight generation)|"); // TODO: this doesn't seem to work + // KLM: this QI cost function is the default + // if (!fp) options.AddWeakSmtOption("smt.QI.COST", "|(+ weight generation)|"); // TODO: this doesn't seem to work //if (options.Inspector != null) // options.WeakAddSmtOption("PROGRESS_SAMPLING_FREQ", "100"); diff --git a/Source/VCGeneration/Check.cs b/Source/VCGeneration/Check.cs index 33baf798..71ae21c6 100644 --- a/Source/VCGeneration/Check.cs +++ b/Source/VCGeneration/Check.cs @@ -449,7 +449,8 @@ namespace Microsoft.Boogie { Invalid, TimeOut, OutOfMemory, - Undetermined + Undetermined, + Bounded } public class ErrorHandler { // Used in CheckOutcomeCore diff --git a/Source/VCGeneration/FixedpointVC.cs b/Source/VCGeneration/FixedpointVC.cs index 5c698633..70ce5a8f 100644 --- a/Source/VCGeneration/FixedpointVC.cs +++ b/Source/VCGeneration/FixedpointVC.cs @@ -480,13 +480,6 @@ namespace Microsoft.Boogie List interfaceVars = new List(); Expr assertExpr = new LiteralExpr(Token.NoToken, true); Contract.Assert(assertExpr != null); - foreach (Variable v in program.GlobalVariables) - { - Contract.Assert(v != null); - interfaceVars.Add(v); - if (v.Name == "error") - inputErrorVariable = v; - } // InParams must be obtained from impl and not proc foreach (Variable v in impl.InParams) { @@ -503,6 +496,13 @@ namespace Microsoft.Boogie Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); assertExpr = Expr.And(assertExpr, eqExpr); } + foreach (Variable v in program.GlobalVariables) + { + Contract.Assert(v != null); + interfaceVars.Add(v); + if (v.Name == "error") + inputErrorVariable = v; + } if (errorVariable != null) { proc.Modifies.Add(new IdentifierExpr(Token.NoToken, errorVariable)); @@ -657,11 +657,6 @@ namespace Microsoft.Boogie } else if (mode == Mode.Corral || proc.FindExprAttribute("inline") != null || proc is LoopProcedure) { - foreach (Variable v in program.GlobalVariables) - { - Contract.Assert(v != null); - exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); - } foreach (Variable v in proc.InParams) { Contract.Assert(v != null); @@ -672,6 +667,11 @@ namespace Microsoft.Boogie Contract.Assert(v != null); exprs.Add(new IdentifierExpr(Token.NoToken, v)); } + foreach (Variable v in program.GlobalVariables) + { + Contract.Assert(v != null); + exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); + } foreach (IdentifierExpr ie in proc.Modifies) { Contract.Assert(ie != null); @@ -1513,7 +1513,7 @@ namespace Microsoft.Boogie /** Check the RPFP, and return a counterexample if there is one. */ - public RPFP.LBool Check(ref RPFP.Node cexroot) + public VC.ConditionGeneration.Outcome Check(ref RPFP.Node cexroot) { var start = DateTime.Now; @@ -1548,11 +1548,15 @@ namespace Microsoft.Boogie switch(outcome) { case ProverInterface.Outcome.Valid: - return RPFP.LBool.False; + return VC.ConditionGeneration.Outcome.Correct; + case ProverInterface.Outcome.Bounded: + return VC.ConditionGeneration.Outcome.ReachedBound; case ProverInterface.Outcome.Invalid: - return RPFP.LBool.True; + return VC.ConditionGeneration.Outcome.Errors; + case ProverInterface.Outcome.TimeOut: + return VC.ConditionGeneration.Outcome.TimedOut; default: - return RPFP.LBool.Undef; + return VC.ConditionGeneration.Outcome.Inconclusive; } } @@ -1598,7 +1602,7 @@ namespace Microsoft.Boogie Console.WriteLine("check: {0}s", (DateTime.Now - start).TotalSeconds); switch (checkres) { - case RPFP.LBool.True: + case Outcome.Errors: Console.WriteLine("Counterexample found.\n"); // start = DateTime.Now; Counterexample cex = CreateBoogieCounterExample(cexroot.owner, cexroot, impl); @@ -1607,17 +1611,23 @@ namespace Microsoft.Boogie collector.OnCounterexample(cex, "assertion failure"); Console.WriteLine("cex: {0}s", (DateTime.Now - start).TotalSeconds); ConjecturesToSpecs(); - return VC.ConditionGeneration.Outcome.Errors; - case RPFP.LBool.False: - Console.WriteLine("Procedure is correct."); + break; + case Outcome.Correct: + Console.WriteLine("Procedure is correct. (fixed point reached)"); FixedPointToSpecs(); ConjecturesToSpecs(); - return Outcome.Correct; - case RPFP.LBool.Undef: + break; + case Outcome.ReachedBound: + Console.WriteLine("Procedure is correct. (recursion bound reached)"); + FixedPointToSpecs(); + ConjecturesToSpecs(); + break; + default: Console.WriteLine("Inconclusive result."); ConjecturesToSpecs(); - return Outcome.ReachedBound; + break; } + return checkres; } -- cgit v1.2.3 From 9c97c7c52776575485c3b131202addb1d864e3d9 Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 10 Jun 2015 10:46:17 -0700 Subject: fixed crash --- Source/Concurrency/TypeCheck.cs | 1519 ++++++++++++++++---------------- Source/Concurrency/YieldTypeChecker.cs | 731 +++++++-------- Source/Provers/SMTLib/SMTLibProcess.cs | 794 ++++++++--------- Test/civl/chris3.bpl | 19 + Test/civl/chris3.bpl.expect | 3 + 5 files changed, 1550 insertions(+), 1516 deletions(-) create mode 100644 Test/civl/chris3.bpl create mode 100644 Test/civl/chris3.bpl.expect diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index c407a7b9..793012e6 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -1,757 +1,764 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie; -using System.Diagnostics.Contracts; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - public enum MoverType - { - Top, - Atomic, - Right, - Left, - Both - } - - public class ActionInfo - { - public Procedure proc; - public int createdAtLayerNum; - public int availableUptoLayerNum; - public bool hasImplementation; - public bool isExtern; - - public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum) - { - this.proc = proc; - this.createdAtLayerNum = createdAtLayerNum; - this.availableUptoLayerNum = availableUptoLayerNum; - this.hasImplementation = false; - this.isExtern = QKeyValue.FindBoolAttribute(proc.Attributes, "extern"); - } - - public virtual bool IsRightMover - { - get { return true; } - } - - public virtual bool IsLeftMover - { - get { return true; } - } - } - - public class AtomicActionInfo : ActionInfo - { - public Ensures ensures; - public MoverType moverType; - public List thisGate; - public CodeExpr thisAction; - public List thisInParams; - public List thisOutParams; - public List thatGate; - public CodeExpr thatAction; - public List thatInParams; - public List thatOutParams; - public HashSet actionUsedGlobalVars; - public HashSet modifiedGlobalVars; - public HashSet gateUsedGlobalVars; - public bool hasAssumeCmd; - - public bool CommutesWith(AtomicActionInfo actionInfo) - { - if (this.modifiedGlobalVars.Intersect(actionInfo.actionUsedGlobalVars).Count() > 0) - return false; - if (this.actionUsedGlobalVars.Intersect(actionInfo.modifiedGlobalVars).Count() > 0) - return false; - return true; - } - - public override bool IsRightMover - { - get { return moverType == MoverType.Right || moverType == MoverType.Both; } - } - - public override bool IsLeftMover - { - get { return moverType == MoverType.Left || moverType == MoverType.Both; } - } - - public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum) - : base(proc, layerNum, availableUptoLayerNum) - { - CodeExpr codeExpr = ensures.Condition as CodeExpr; - this.ensures = ensures; - this.moverType = moverType; - this.thisGate = new List(); - this.thisAction = codeExpr; - this.thisInParams = new List(); - this.thisOutParams = new List(); - this.thatGate = new List(); - this.thatInParams = new List(); - this.thatOutParams = new List(); - this.hasAssumeCmd = false; - - foreach (Block block in codeExpr.Blocks) - { - block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd); - } - - var cmds = thisAction.Blocks[0].Cmds; - for (int i = 0; i < cmds.Count; i++) - { - AssertCmd assertCmd = cmds[i] as AssertCmd; - if (assertCmd == null) break; - thisGate.Add(assertCmd); - cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True); - } - - Dictionary map = new Dictionary(); - foreach (Variable x in proc.InParams) - { - this.thisInParams.Add(x); - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); - this.thatInParams.Add(y); - map[x] = Expr.Ident(y); - } - foreach (Variable x in proc.OutParams) - { - this.thisOutParams.Add(x); - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); - this.thatOutParams.Add(y); - map[x] = Expr.Ident(y); - } - List thatLocVars = new List(); - foreach (Variable x in thisAction.LocVars) - { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); - map[x] = Expr.Ident(y); - thatLocVars.Add(y); - } - Contract.Assume(proc.TypeParameters.Count == 0); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (AssertCmd assertCmd in thisGate) - { - thatGate.Add((AssertCmd)Substituter.Apply(subst, assertCmd)); - } - Dictionary blockMap = new Dictionary(); - List thatBlocks = new List(); - foreach (Block block in thisAction.Blocks) - { - List otherCmds = new List(); - foreach (Cmd cmd in block.Cmds) - { - otherCmds.Add(Substituter.Apply(subst, cmd)); - } - Block thatBlock = new Block(); - thatBlock.Cmds = otherCmds; - thatBlock.Label = "that_" + block.Label; - block.Label = "this_" + block.Label; - thatBlocks.Add(thatBlock); - blockMap[block] = thatBlock; - if (block.TransferCmd is GotoCmd) - { - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - for (int i = 0; i < gotoCmd.labelNames.Count; i++) - { - gotoCmd.labelNames[i] = "this_" + gotoCmd.labelNames[i]; - } - } - } - foreach (Block block in thisAction.Blocks) - { - if (block.TransferCmd is ReturnExprCmd) - { - block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); - blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok); - continue; - } - List thatGotoCmdLabelTargets = new List(); - List thatGotoCmdLabelNames = new List(); - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - thatGotoCmdLabelTargets.Add(blockMap[target]); - thatGotoCmdLabelNames.Add(blockMap[target].Label); - } - blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, thatGotoCmdLabelNames, thatGotoCmdLabelTargets); - } - this.thatAction = new CodeExpr(thatLocVars, thatBlocks); - - { - VariableCollector collector = new VariableCollector(); - collector.Visit(codeExpr); - this.actionUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); - } - - List modifiedVars = new List(); - foreach (Block block in codeExpr.Blocks) - { - block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); - } - this.modifiedGlobalVars = new HashSet(modifiedVars.Where(x => x is GlobalVariable)); - - { - VariableCollector collector = new VariableCollector(); - this.thisGate.ForEach(assertCmd => collector.Visit(assertCmd)); - this.gateUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); - } - } - } - - public class SharedVariableInfo - { - public int introLayerNum; - public int hideLayerNum; - - public SharedVariableInfo(int introLayerNum, int hideLayerNum) - { - this.introLayerNum = introLayerNum; - this.hideLayerNum = hideLayerNum; - } - } - - public class LayerEraser : ReadOnlyVisitor - { - private QKeyValue RemoveLayerAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveLayerAttribute(iter.Next); - return (iter.Key == "layer") ? iter.Next : iter; - } - - public override Variable VisitVariable(Variable node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitVariable(node); - } - - public override Procedure VisitProcedure(Procedure node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitProcedure(node); - } - - public override Implementation VisitImplementation(Implementation node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitImplementation(node); - } - - public override Requires VisitRequires(Requires node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitRequires(node); - } - - public override Ensures VisitEnsures(Ensures node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitEnsures(node); - } - - public override Cmd VisitAssertCmd(AssertCmd node) - { - node.Attributes = RemoveLayerAttribute(node.Attributes); - return base.VisitAssertCmd(node); - } - } - - public class MoverTypeChecker : ReadOnlyVisitor - { - CheckingContext checkingContext; - public int errorCount; - public Dictionary globalVarToSharedVarInfo; - Procedure enclosingProc; - Implementation enclosingImpl; - public Dictionary procToActionInfo; - public Program program; - bool canAccessSharedVars; - bool canAccessGhostVars; - int minLayerNum; - int maxLayerNum; - public Dictionary> absyToLayerNums; - HashSet ghostVars; - public int leastUnimplementedLayerNum; - - private static List FindLayers(QKeyValue kv) - { - HashSet attrs = new HashSet(); - for (; kv != null; kv = kv.Next) - { - if (kv.Key != "layer") continue; - foreach (var o in kv.Params) - { - Expr e = o as Expr; - if (e == null) continue; - LiteralExpr l = e as LiteralExpr; - if (l != null && l.isBigNum) - attrs.Add(l.asBigNum.ToIntSafe); - } - } - List layers = attrs.ToList(); - layers.Sort(); - return layers; - } - - private static MoverType GetMoverType(Ensures e) - { - if (QKeyValue.FindBoolAttribute(e.Attributes, "atomic")) - return MoverType.Atomic; - if (QKeyValue.FindBoolAttribute(e.Attributes, "right")) - return MoverType.Right; - if (QKeyValue.FindBoolAttribute(e.Attributes, "left")) - return MoverType.Left; - if (QKeyValue.FindBoolAttribute(e.Attributes, "both")) - return MoverType.Both; - return MoverType.Top; - } - - public MoverTypeChecker(Program program) - { - this.ghostVars = new HashSet(); - this.absyToLayerNums = new Dictionary>(); - this.globalVarToSharedVarInfo = new Dictionary(); - this.procToActionInfo = new Dictionary(); - this.errorCount = 0; - this.checkingContext = new CheckingContext(null); - this.program = program; - this.enclosingProc = null; - this.enclosingImpl = null; - this.canAccessSharedVars = false; - this.canAccessGhostVars = false; - this.minLayerNum = int.MaxValue; - this.maxLayerNum = -1; - this.leastUnimplementedLayerNum = int.MaxValue; - foreach (var g in program.GlobalVariables) - { - List layerNums = FindLayers(g.Attributes); - if (layerNums.Count == 0) - { - // Cannot access atomic actions - } - else if (layerNums.Count == 1) - { - this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], int.MaxValue); - } - else if (layerNums.Count == 2) - { - this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], layerNums[1]); - } - else - { - Error(g, "Too many layer numbers"); - } - } - } - - private HashSet allCreatedLayerNums; - public IEnumerable AllCreatedLayerNums - { - get - { - if (allCreatedLayerNums == null) - { - allCreatedLayerNums = new HashSet(); - foreach (ActionInfo actionInfo in procToActionInfo.Values) - { - allCreatedLayerNums.Add(actionInfo.createdAtLayerNum); - } - } - return allCreatedLayerNums; - } - } - - public void TypeCheck() - { - foreach (var proc in program.Procedures) - { - if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; - - int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error - int availableUptoLayerNum = int.MaxValue; - List attrs = FindLayers(proc.Attributes); - if (attrs.Count == 1) - { - createdAtLayerNum = attrs[0]; - } - else if (attrs.Count == 2) - { - createdAtLayerNum = attrs[0]; - availableUptoLayerNum = attrs[1]; - } - else - { - Error(proc, "Incorrect number of layers"); - continue; - } - if (availableUptoLayerNum <= createdAtLayerNum) - { - Error(proc, "Creation layer number must be less than the available upto layer number"); - continue; - } - foreach (Ensures e in proc.Ensures) - { - MoverType moverType = GetMoverType(e); - if (moverType == MoverType.Top) continue; - CodeExpr codeExpr = e.Condition as CodeExpr; - if (codeExpr == null) - { - Error(e, "An atomic action must be a CodeExpr"); - continue; - } - if (procToActionInfo.ContainsKey(proc)) - { - Error(proc, "A procedure can have at most one atomic action"); - continue; - } - - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - enclosingProc = proc; - enclosingImpl = null; - base.VisitEnsures(e); - canAccessSharedVars = false; - if (maxLayerNum > createdAtLayerNum) - { - Error(e, "A variable being accessed is introduced after this action is created"); - } - else if (availableUptoLayerNum > minLayerNum) - { - Error(e, "A variable being accessed is hidden before this action becomes unavailable"); - } - else - { - procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); - } - } - if (errorCount > 0) continue; - if (!procToActionInfo.ContainsKey(proc)) - { - procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); - } - } - if (errorCount > 0) return; - foreach (var impl in program.Implementations) - { - if (!procToActionInfo.ContainsKey(impl.Proc)) continue; - procToActionInfo[impl.Proc].hasImplementation = true; - } - foreach (var proc in procToActionInfo.Keys) - { - ActionInfo actionInfo = procToActionInfo[proc]; - if (actionInfo.isExtern && actionInfo.hasImplementation) - { - Error(proc, "Extern procedure cannot have an implementation"); - continue; - } - if (actionInfo.isExtern || actionInfo.hasImplementation) continue; - if (leastUnimplementedLayerNum == int.MaxValue) - { - leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; - } - else if (leastUnimplementedLayerNum != actionInfo.createdAtLayerNum) - { - Error(proc, "All unimplemented atomic actions must be created at the same layer"); - } - } - foreach (var g in this.globalVarToSharedVarInfo.Keys) - { - var info = globalVarToSharedVarInfo[g]; - if (!this.AllCreatedLayerNums.Contains(info.introLayerNum)) - { - Error(g, "Variable must be introduced with creation of some atomic action"); - } - if (info.hideLayerNum != int.MaxValue && !this.AllCreatedLayerNums.Contains(info.hideLayerNum)) - { - Error(g, "Variable must be hidden with creation of some atomic action"); - } - } - if (errorCount > 0) return; - this.VisitProgram(program); - foreach (Procedure proc in program.Procedures) - { - if (procToActionInfo.ContainsKey(proc)) continue; - foreach (var ie in proc.Modifies) - { - if (!SharedVariables.Contains(ie.Decl)) continue; - Error(proc, "A ghost procedure must not modify a global variable with layer annotation"); - } - } - if (errorCount > 0) return; - YieldTypeChecker.PerformYieldSafeCheck(this); - new LayerEraser().VisitProgram(program); - } - - public IEnumerable SharedVariables - { - get { return this.globalVarToSharedVarInfo.Keys; } - } - - public override Implementation VisitImplementation(Implementation node) - { - if (!procToActionInfo.ContainsKey(node.Proc)) - { - return node; - } - this.enclosingImpl = node; - this.enclosingProc = null; - ghostVars = new HashSet(); - foreach (Variable v in node.LocVars) - { - if (QKeyValue.FindBoolAttribute(v.Attributes, "ghost")) - { - ghostVars.Add(v); - } - } - return base.VisitImplementation(node); - } - - public override Procedure VisitProcedure(Procedure node) - { - if (!procToActionInfo.ContainsKey(node)) - { - return node; - } - this.enclosingProc = node; - this.enclosingImpl = null; - return base.VisitProcedure(node); - } - - public override Cmd VisitCallCmd(CallCmd node) - { - int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; - if (procToActionInfo.ContainsKey(node.Proc)) - { - ActionInfo actionInfo = procToActionInfo[node.Proc]; - if (node.IsAsync && actionInfo is AtomicActionInfo) - { - Error(node, "Target of async call cannot be an atomic action"); - } - int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum; - if (enclosingProcLayerNum < calleeLayerNum || - (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo)) - { - Error(node, "The layer of the caller must be greater than the layer of the callee"); - } - else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0) - { - HashSet outParams = new HashSet(enclosingImpl.OutParams); - foreach (var x in node.Outs) - { - if (x.Decl is GlobalVariable) - { - Error(node, "A global variable cannot be used as output argument for this call"); - } - else if (outParams.Contains(x.Decl)) - { - Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call"); - } - } - } - if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum) - { - Error(node, "The callee is not available in the caller procedure"); - } - return base.VisitCallCmd(node); - } - else - { - foreach (var ie in node.Outs) - { - if (ghostVars.Contains(ie.Decl)) continue; - Error(node, "The output of a ghost procedure must be assigned to a ghost variable"); - } - bool savedCanAccessSharedVars = canAccessSharedVars; - bool savedCanAccessAuxVars = canAccessGhostVars; - canAccessSharedVars = true; - canAccessGhostVars = true; - var retVal = base.VisitCallCmd(node); - canAccessSharedVars = savedCanAccessSharedVars; - canAccessGhostVars = savedCanAccessAuxVars; - return retVal; - } - } - - public override Cmd VisitParCallCmd(ParCallCmd node) - { - int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; - bool isLeftMover = true; - bool isRightMover = true; - int maxCalleeLayerNum = 0; - int atomicActionCalleeLayerNum = 0; - int numAtomicActions = 0; - foreach (CallCmd iter in node.CallCmds) - { - ActionInfo actionInfo = procToActionInfo[iter.Proc]; - isLeftMover = isLeftMover && actionInfo.IsLeftMover; - isRightMover = isRightMover && actionInfo.IsRightMover; - if (actionInfo.createdAtLayerNum > maxCalleeLayerNum) - { - maxCalleeLayerNum = actionInfo.createdAtLayerNum; - } - if (actionInfo is AtomicActionInfo) - { - numAtomicActions++; - if (atomicActionCalleeLayerNum == 0) - { - atomicActionCalleeLayerNum = actionInfo.createdAtLayerNum; - } - else if (atomicActionCalleeLayerNum != actionInfo.createdAtLayerNum) - { - Error(node, "All atomic actions must be introduced at the same layer"); - } - } - } - if (numAtomicActions > 1 && !isLeftMover && !isRightMover) - { - Error(node, "The atomic actions in the parallel call must be all right movers or all left movers"); - } - if (0 < atomicActionCalleeLayerNum && atomicActionCalleeLayerNum < maxCalleeLayerNum) - { - Error(node, "Atomic actions must be introduced at the highest layer"); - } - return base.VisitParCallCmd(node); - } - - public override Cmd VisitAssignCmd(AssignCmd node) - { - Contract.Ensures(Contract.Result() == node); - for (int i = 0; i < node.Lhss.Count; ++i) - { - bool savedCanAccessSharedVars = canAccessSharedVars; - bool savedCanAccessAuxVars = canAccessGhostVars; - Variable v = node.Lhss[i].DeepAssignedVariable; - if (v is LocalVariable && ghostVars.Contains(v)) - { - canAccessSharedVars = true; - canAccessGhostVars = true; - } - this.Visit(node.Lhss[i]); - this.Visit(node.Rhss[i]); - canAccessSharedVars = savedCanAccessSharedVars; - canAccessGhostVars = savedCanAccessAuxVars; - } - return node; - } - - public override Expr VisitIdentifierExpr(IdentifierExpr node) - { - if (node.Decl is GlobalVariable) - { - if (!canAccessSharedVars) - { - Error(node, "Shared variable can be accessed only in atomic actions or specifications"); - } - else if (this.globalVarToSharedVarInfo.ContainsKey(node.Decl)) - { - if (this.globalVarToSharedVarInfo[node.Decl].hideLayerNum < minLayerNum) - { - minLayerNum = this.globalVarToSharedVarInfo[node.Decl].hideLayerNum; - } - if (this.globalVarToSharedVarInfo[node.Decl].introLayerNum > maxLayerNum) - { - maxLayerNum = this.globalVarToSharedVarInfo[node.Decl].introLayerNum; - } - } - else - { - Error(node, "Accessed shared variable must have layer annotation"); - } - } - else if (node.Decl is LocalVariable && ghostVars.Contains(node.Decl) && !canAccessGhostVars) - { - Error(node, "Ghost variable can be accessed only in assertions"); - } - - return base.VisitIdentifierExpr(node); - } - - public override Ensures VisitEnsures(Ensures ensures) - { - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - Ensures ret = base.VisitEnsures(ensures); - canAccessSharedVars = false; - ActionInfo actionInfo = procToActionInfo[enclosingProc]; - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo != null && atomicActionInfo.ensures == ensures) - { - // This case has already been checked - } - else - { - CheckAndAddLayers(ensures, ensures.Attributes, actionInfo.createdAtLayerNum); - } - return ret; - } - - public override Requires VisitRequires(Requires requires) - { - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - Requires ret = base.VisitRequires(requires); - canAccessSharedVars = false; - CheckAndAddLayers(requires, requires.Attributes, procToActionInfo[enclosingProc].createdAtLayerNum); - return ret; - } - - public override Cmd VisitAssertCmd(AssertCmd node) - { - if (enclosingImpl == null) - return base.VisitAssertCmd(node); - minLayerNum = int.MaxValue; - maxLayerNum = -1; - canAccessSharedVars = true; - canAccessGhostVars = true; - Cmd ret = base.VisitAssertCmd(node); - canAccessGhostVars = false; - canAccessSharedVars = false; - CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum); - return ret; - } - - private void CheckAndAddLayers(Absy node, QKeyValue attributes, int enclosingProcLayerNum) - { - List attrs = FindLayers(attributes); - if (attrs.Count == 0) - { - Error(node, "layer not present"); - return; - } - absyToLayerNums[node] = new HashSet(); - foreach (int layerNum in attrs) - { - if (layerNum == leastUnimplementedLayerNum || !AllCreatedLayerNums.Contains(layerNum)) - { - Error(node, "Illegal layer number"); - } - else if (layerNum > enclosingProcLayerNum) - { - Error(node, "The layer cannot be greater than the layer of enclosing procedure"); - } - else if (maxLayerNum < layerNum && layerNum <= minLayerNum) - { - absyToLayerNums[node].Add(layerNum); - } - else - { - Error(node, string.Format("A variable being accessed in this specification is unavailable at layer {0}", layerNum)); - } - } - } - - public void Error(Absy node, string message) - { - checkingContext.Error(node, message); - errorCount++; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public enum MoverType + { + Top, + Atomic, + Right, + Left, + Both + } + + public class ActionInfo + { + public Procedure proc; + public int createdAtLayerNum; + public int availableUptoLayerNum; + public bool hasImplementation; + public bool isExtern; + + public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum) + { + this.proc = proc; + this.createdAtLayerNum = createdAtLayerNum; + this.availableUptoLayerNum = availableUptoLayerNum; + this.hasImplementation = false; + this.isExtern = QKeyValue.FindBoolAttribute(proc.Attributes, "extern"); + } + + public virtual bool IsRightMover + { + get { return true; } + } + + public virtual bool IsLeftMover + { + get { return true; } + } + } + + public class AtomicActionInfo : ActionInfo + { + public Ensures ensures; + public MoverType moverType; + public List thisGate; + public CodeExpr thisAction; + public List thisInParams; + public List thisOutParams; + public List thatGate; + public CodeExpr thatAction; + public List thatInParams; + public List thatOutParams; + public HashSet actionUsedGlobalVars; + public HashSet modifiedGlobalVars; + public HashSet gateUsedGlobalVars; + public bool hasAssumeCmd; + + public bool CommutesWith(AtomicActionInfo actionInfo) + { + if (this.modifiedGlobalVars.Intersect(actionInfo.actionUsedGlobalVars).Count() > 0) + return false; + if (this.actionUsedGlobalVars.Intersect(actionInfo.modifiedGlobalVars).Count() > 0) + return false; + return true; + } + + public override bool IsRightMover + { + get { return moverType == MoverType.Right || moverType == MoverType.Both; } + } + + public override bool IsLeftMover + { + get { return moverType == MoverType.Left || moverType == MoverType.Both; } + } + + public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum) + : base(proc, layerNum, availableUptoLayerNum) + { + CodeExpr codeExpr = ensures.Condition as CodeExpr; + this.ensures = ensures; + this.moverType = moverType; + this.thisGate = new List(); + this.thisAction = codeExpr; + this.thisInParams = new List(); + this.thisOutParams = new List(); + this.thatGate = new List(); + this.thatInParams = new List(); + this.thatOutParams = new List(); + this.hasAssumeCmd = false; + + foreach (Block block in codeExpr.Blocks) + { + block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd); + } + + var cmds = thisAction.Blocks[0].Cmds; + for (int i = 0; i < cmds.Count; i++) + { + AssertCmd assertCmd = cmds[i] as AssertCmd; + if (assertCmd == null) break; + thisGate.Add(assertCmd); + cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True); + } + + Dictionary map = new Dictionary(); + foreach (Variable x in proc.InParams) + { + this.thisInParams.Add(x); + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thatInParams.Add(y); + map[x] = Expr.Ident(y); + } + foreach (Variable x in proc.OutParams) + { + this.thisOutParams.Add(x); + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thatOutParams.Add(y); + map[x] = Expr.Ident(y); + } + List thatLocVars = new List(); + foreach (Variable x in thisAction.LocVars) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); + map[x] = Expr.Ident(y); + thatLocVars.Add(y); + } + Contract.Assume(proc.TypeParameters.Count == 0); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (AssertCmd assertCmd in thisGate) + { + thatGate.Add((AssertCmd)Substituter.Apply(subst, assertCmd)); + } + Dictionary blockMap = new Dictionary(); + List thatBlocks = new List(); + foreach (Block block in thisAction.Blocks) + { + List otherCmds = new List(); + foreach (Cmd cmd in block.Cmds) + { + otherCmds.Add(Substituter.Apply(subst, cmd)); + } + Block thatBlock = new Block(); + thatBlock.Cmds = otherCmds; + thatBlock.Label = "that_" + block.Label; + block.Label = "this_" + block.Label; + thatBlocks.Add(thatBlock); + blockMap[block] = thatBlock; + if (block.TransferCmd is GotoCmd) + { + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + for (int i = 0; i < gotoCmd.labelNames.Count; i++) + { + gotoCmd.labelNames[i] = "this_" + gotoCmd.labelNames[i]; + } + } + } + foreach (Block block in thisAction.Blocks) + { + if (block.TransferCmd is ReturnExprCmd) + { + block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); + blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok); + continue; + } + List thatGotoCmdLabelTargets = new List(); + List thatGotoCmdLabelNames = new List(); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + thatGotoCmdLabelTargets.Add(blockMap[target]); + thatGotoCmdLabelNames.Add(blockMap[target].Label); + } + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, thatGotoCmdLabelNames, thatGotoCmdLabelTargets); + } + this.thatAction = new CodeExpr(thatLocVars, thatBlocks); + + { + VariableCollector collector = new VariableCollector(); + collector.Visit(codeExpr); + this.actionUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); + } + + List modifiedVars = new List(); + foreach (Block block in codeExpr.Blocks) + { + block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); + } + this.modifiedGlobalVars = new HashSet(modifiedVars.Where(x => x is GlobalVariable)); + + { + VariableCollector collector = new VariableCollector(); + this.thisGate.ForEach(assertCmd => collector.Visit(assertCmd)); + this.gateUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); + } + } + } + + public class SharedVariableInfo + { + public int introLayerNum; + public int hideLayerNum; + + public SharedVariableInfo(int introLayerNum, int hideLayerNum) + { + this.introLayerNum = introLayerNum; + this.hideLayerNum = hideLayerNum; + } + } + + public class LayerEraser : ReadOnlyVisitor + { + private QKeyValue RemoveLayerAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveLayerAttribute(iter.Next); + return (iter.Key == "layer") ? iter.Next : iter; + } + + public override Variable VisitVariable(Variable node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitVariable(node); + } + + public override Procedure VisitProcedure(Procedure node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitProcedure(node); + } + + public override Implementation VisitImplementation(Implementation node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitImplementation(node); + } + + public override Requires VisitRequires(Requires node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitRequires(node); + } + + public override Ensures VisitEnsures(Ensures node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitEnsures(node); + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitAssertCmd(node); + } + } + + public class MoverTypeChecker : ReadOnlyVisitor + { + CheckingContext checkingContext; + public int errorCount; + public Dictionary globalVarToSharedVarInfo; + Procedure enclosingProc; + Implementation enclosingImpl; + public Dictionary procToActionInfo; + public Program program; + bool canAccessSharedVars; + bool canAccessGhostVars; + int minLayerNum; + int maxLayerNum; + public Dictionary> absyToLayerNums; + HashSet ghostVars; + public int leastUnimplementedLayerNum; + + private static List FindLayers(QKeyValue kv) + { + List layers = new List(); + for (; kv != null; kv = kv.Next) + { + if (kv.Key != "layer") continue; + foreach (var o in kv.Params) + { + Expr e = o as Expr; + if (e == null) return null; + LiteralExpr l = e as LiteralExpr; + if (l == null) return null; + if (!l.isBigNum) return null; + layers.Add(l.asBigNum.ToIntSafe); + } + } + return layers; + } + + private static MoverType GetMoverType(Ensures e) + { + if (QKeyValue.FindBoolAttribute(e.Attributes, "atomic")) + return MoverType.Atomic; + if (QKeyValue.FindBoolAttribute(e.Attributes, "right")) + return MoverType.Right; + if (QKeyValue.FindBoolAttribute(e.Attributes, "left")) + return MoverType.Left; + if (QKeyValue.FindBoolAttribute(e.Attributes, "both")) + return MoverType.Both; + return MoverType.Top; + } + + public MoverTypeChecker(Program program) + { + this.ghostVars = new HashSet(); + this.absyToLayerNums = new Dictionary>(); + this.globalVarToSharedVarInfo = new Dictionary(); + this.procToActionInfo = new Dictionary(); + this.errorCount = 0; + this.checkingContext = new CheckingContext(null); + this.program = program; + this.enclosingProc = null; + this.enclosingImpl = null; + this.canAccessSharedVars = false; + this.canAccessGhostVars = false; + this.minLayerNum = int.MaxValue; + this.maxLayerNum = -1; + this.leastUnimplementedLayerNum = int.MaxValue; + foreach (var g in program.GlobalVariables) + { + List layerNums = FindLayers(g.Attributes); + if (layerNums.Count == 0) + { + // Cannot access atomic actions + } + else if (layerNums.Count == 1) + { + this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], int.MaxValue); + } + else if (layerNums.Count == 2) + { + this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], layerNums[1]); + } + else + { + Error(g, "Too many layer numbers"); + } + } + } + + private HashSet allCreatedLayerNums; + public IEnumerable AllCreatedLayerNums + { + get + { + if (allCreatedLayerNums == null) + { + allCreatedLayerNums = new HashSet(); + foreach (ActionInfo actionInfo in procToActionInfo.Values) + { + allCreatedLayerNums.Add(actionInfo.createdAtLayerNum); + } + } + return allCreatedLayerNums; + } + } + + public void TypeCheck() + { + foreach (var proc in program.Procedures) + { + if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; + + int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error + int availableUptoLayerNum = int.MaxValue; + List attrs = FindLayers(proc.Attributes); + if (attrs.Count == 1) + { + createdAtLayerNum = attrs[0]; + } + else if (attrs.Count == 2) + { + createdAtLayerNum = attrs[0]; + availableUptoLayerNum = attrs[1]; + } + else + { + Error(proc, "Incorrect number of layers"); + continue; + } + if (availableUptoLayerNum <= createdAtLayerNum) + { + Error(proc, "Creation layer number must be less than the available upto layer number"); + continue; + } + foreach (Ensures e in proc.Ensures) + { + MoverType moverType = GetMoverType(e); + if (moverType == MoverType.Top) continue; + CodeExpr codeExpr = e.Condition as CodeExpr; + if (codeExpr == null) + { + Error(e, "An atomic action must be a CodeExpr"); + continue; + } + if (procToActionInfo.ContainsKey(proc)) + { + Error(proc, "A procedure can have at most one atomic action"); + continue; + } + + minLayerNum = int.MaxValue; + maxLayerNum = -1; + canAccessSharedVars = true; + enclosingProc = proc; + enclosingImpl = null; + base.VisitEnsures(e); + canAccessSharedVars = false; + if (maxLayerNum > createdAtLayerNum) + { + Error(e, "A variable being accessed is introduced after this action is created"); + } + else if (availableUptoLayerNum > minLayerNum) + { + Error(e, "A variable being accessed is hidden before this action becomes unavailable"); + } + else + { + procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); + } + } + if (errorCount > 0) continue; + if (!procToActionInfo.ContainsKey(proc)) + { + procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); + } + } + if (errorCount > 0) return; + foreach (var impl in program.Implementations) + { + if (!procToActionInfo.ContainsKey(impl.Proc)) continue; + procToActionInfo[impl.Proc].hasImplementation = true; + } + foreach (var proc in procToActionInfo.Keys) + { + ActionInfo actionInfo = procToActionInfo[proc]; + if (actionInfo.isExtern && actionInfo.hasImplementation) + { + Error(proc, "Extern procedure cannot have an implementation"); + continue; + } + if (actionInfo.isExtern || actionInfo.hasImplementation) continue; + if (leastUnimplementedLayerNum == int.MaxValue) + { + leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; + } + else if (leastUnimplementedLayerNum != actionInfo.createdAtLayerNum) + { + Error(proc, "All unimplemented atomic actions must be created at the same layer"); + } + } + foreach (var g in this.globalVarToSharedVarInfo.Keys) + { + var info = globalVarToSharedVarInfo[g]; + if (!this.AllCreatedLayerNums.Contains(info.introLayerNum)) + { + Error(g, "Variable must be introduced with creation of some atomic action"); + } + if (info.hideLayerNum != int.MaxValue && !this.AllCreatedLayerNums.Contains(info.hideLayerNum)) + { + Error(g, "Variable must be hidden with creation of some atomic action"); + } + } + if (errorCount > 0) return; + this.VisitProgram(program); + foreach (Procedure proc in program.Procedures) + { + if (procToActionInfo.ContainsKey(proc)) continue; + foreach (var ie in proc.Modifies) + { + if (!SharedVariables.Contains(ie.Decl)) continue; + Error(proc, "A ghost procedure must not modify a global variable with layer annotation"); + } + } + if (errorCount > 0) return; + YieldTypeChecker.PerformYieldSafeCheck(this); + new LayerEraser().VisitProgram(program); + } + + public IEnumerable SharedVariables + { + get { return this.globalVarToSharedVarInfo.Keys; } + } + + public override Implementation VisitImplementation(Implementation node) + { + if (!procToActionInfo.ContainsKey(node.Proc)) + { + return node; + } + this.enclosingImpl = node; + this.enclosingProc = null; + ghostVars = new HashSet(); + foreach (Variable v in node.LocVars) + { + if (QKeyValue.FindBoolAttribute(v.Attributes, "ghost")) + { + ghostVars.Add(v); + } + } + return base.VisitImplementation(node); + } + + public override Procedure VisitProcedure(Procedure node) + { + if (!procToActionInfo.ContainsKey(node)) + { + return node; + } + this.enclosingProc = node; + this.enclosingImpl = null; + return base.VisitProcedure(node); + } + + public override Cmd VisitCallCmd(CallCmd node) + { + int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + if (procToActionInfo.ContainsKey(node.Proc)) + { + ActionInfo actionInfo = procToActionInfo[node.Proc]; + if (node.IsAsync && actionInfo is AtomicActionInfo) + { + Error(node, "Target of async call cannot be an atomic action"); + } + int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum; + if (enclosingProcLayerNum < calleeLayerNum || + (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo)) + { + Error(node, "The layer of the caller must be greater than the layer of the callee"); + } + else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0) + { + HashSet outParams = new HashSet(enclosingImpl.OutParams); + foreach (var x in node.Outs) + { + if (x.Decl is GlobalVariable) + { + Error(node, "A global variable cannot be used as output argument for this call"); + } + else if (outParams.Contains(x.Decl)) + { + Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call"); + } + } + } + if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum) + { + Error(node, "The callee is not available in the caller procedure"); + } + return base.VisitCallCmd(node); + } + else + { + foreach (var ie in node.Outs) + { + if (ghostVars.Contains(ie.Decl)) continue; + Error(node, "The output of a ghost procedure must be assigned to a ghost variable"); + } + bool savedCanAccessSharedVars = canAccessSharedVars; + bool savedCanAccessAuxVars = canAccessGhostVars; + canAccessSharedVars = true; + canAccessGhostVars = true; + var retVal = base.VisitCallCmd(node); + canAccessSharedVars = savedCanAccessSharedVars; + canAccessGhostVars = savedCanAccessAuxVars; + return retVal; + } + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + bool isLeftMover = true; + bool isRightMover = true; + int maxCalleeLayerNum = 0; + int atomicActionCalleeLayerNum = 0; + int numAtomicActions = 0; + foreach (CallCmd iter in node.CallCmds) + { + ActionInfo actionInfo = procToActionInfo[iter.Proc]; + isLeftMover = isLeftMover && actionInfo.IsLeftMover; + isRightMover = isRightMover && actionInfo.IsRightMover; + if (actionInfo.createdAtLayerNum > maxCalleeLayerNum) + { + maxCalleeLayerNum = actionInfo.createdAtLayerNum; + } + if (actionInfo is AtomicActionInfo) + { + numAtomicActions++; + if (atomicActionCalleeLayerNum == 0) + { + atomicActionCalleeLayerNum = actionInfo.createdAtLayerNum; + } + else if (atomicActionCalleeLayerNum != actionInfo.createdAtLayerNum) + { + Error(node, "All atomic actions must be introduced at the same layer"); + } + } + } + if (numAtomicActions > 1 && !isLeftMover && !isRightMover) + { + Error(node, "The atomic actions in the parallel call must be all right movers or all left movers"); + } + if (0 < atomicActionCalleeLayerNum && atomicActionCalleeLayerNum < maxCalleeLayerNum) + { + Error(node, "Atomic actions must be introduced at the highest layer"); + } + return base.VisitParCallCmd(node); + } + + public override Cmd VisitAssignCmd(AssignCmd node) + { + Contract.Ensures(Contract.Result() == node); + for (int i = 0; i < node.Lhss.Count; ++i) + { + bool savedCanAccessSharedVars = canAccessSharedVars; + bool savedCanAccessAuxVars = canAccessGhostVars; + Variable v = node.Lhss[i].DeepAssignedVariable; + if (v is LocalVariable && ghostVars.Contains(v)) + { + canAccessSharedVars = true; + canAccessGhostVars = true; + } + this.Visit(node.Lhss[i]); + this.Visit(node.Rhss[i]); + canAccessSharedVars = savedCanAccessSharedVars; + canAccessGhostVars = savedCanAccessAuxVars; + } + return node; + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + if (node.Decl is GlobalVariable) + { + if (!canAccessSharedVars) + { + Error(node, "Shared variable can be accessed only in atomic actions or specifications"); + } + else if (this.globalVarToSharedVarInfo.ContainsKey(node.Decl)) + { + if (this.globalVarToSharedVarInfo[node.Decl].hideLayerNum < minLayerNum) + { + minLayerNum = this.globalVarToSharedVarInfo[node.Decl].hideLayerNum; + } + if (this.globalVarToSharedVarInfo[node.Decl].introLayerNum > maxLayerNum) + { + maxLayerNum = this.globalVarToSharedVarInfo[node.Decl].introLayerNum; + } + } + else + { + Error(node, "Accessed shared variable must have layer annotation"); + } + } + else if (node.Decl is LocalVariable && ghostVars.Contains(node.Decl) && !canAccessGhostVars) + { + Error(node, "Ghost variable can be accessed only in assertions"); + } + + return base.VisitIdentifierExpr(node); + } + + public override Ensures VisitEnsures(Ensures ensures) + { + minLayerNum = int.MaxValue; + maxLayerNum = -1; + canAccessSharedVars = true; + Ensures ret = base.VisitEnsures(ensures); + canAccessSharedVars = false; + ActionInfo actionInfo = procToActionInfo[enclosingProc]; + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo != null && atomicActionInfo.ensures == ensures) + { + // This case has already been checked + } + else + { + CheckAndAddLayers(ensures, ensures.Attributes, actionInfo.createdAtLayerNum); + } + return ret; + } + + public override Requires VisitRequires(Requires requires) + { + minLayerNum = int.MaxValue; + maxLayerNum = -1; + canAccessSharedVars = true; + Requires ret = base.VisitRequires(requires); + canAccessSharedVars = false; + CheckAndAddLayers(requires, requires.Attributes, procToActionInfo[enclosingProc].createdAtLayerNum); + return ret; + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + if (enclosingImpl == null) + return base.VisitAssertCmd(node); + minLayerNum = int.MaxValue; + maxLayerNum = -1; + canAccessSharedVars = true; + canAccessGhostVars = true; + Cmd ret = base.VisitAssertCmd(node); + canAccessGhostVars = false; + canAccessSharedVars = false; + CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum); + return ret; + } + + private List RemoveDuplicatesAndSort(List attrs) + { + HashSet layerSet = new HashSet(attrs); + List layers = new List(layerSet); + layers.Sort(); + return layers; + } + + private void CheckAndAddLayers(Absy node, QKeyValue attributes, int enclosingProcLayerNum) + { + List attrs = RemoveDuplicatesAndSort(FindLayers(attributes)); + if (attrs.Count == 0) + { + Error(node, "layer not present"); + return; + } + absyToLayerNums[node] = new HashSet(); + foreach (int layerNum in attrs) + { + if (layerNum == leastUnimplementedLayerNum || !AllCreatedLayerNums.Contains(layerNum)) + { + Error(node, "Illegal layer number"); + } + else if (layerNum > enclosingProcLayerNum) + { + Error(node, "The layer cannot be greater than the layer of enclosing procedure"); + } + else if (maxLayerNum < layerNum && layerNum <= minLayerNum) + { + absyToLayerNums[node].Add(layerNum); + } + else + { + Error(node, string.Format("A variable being accessed in this specification is unavailable at layer {0}", layerNum)); + } + } + } + + public void Error(Absy node, string message) + { + checkingContext.Error(node, message); + errorCount++; + } + } } \ No newline at end of file diff --git a/Source/Concurrency/YieldTypeChecker.cs b/Source/Concurrency/YieldTypeChecker.cs index 95884626..a698c8fd 100644 --- a/Source/Concurrency/YieldTypeChecker.cs +++ b/Source/Concurrency/YieldTypeChecker.cs @@ -1,363 +1,368 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.AbstractInterpretation; -using Microsoft.Boogie.GraphUtil; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - class YieldTypeChecker - { - static List> ASpec; - static List> BSpec; - static List> CSpec; - static YieldTypeChecker() - { - // initial: 0, final: 1 - ASpec = new List>(); - ASpec.Add(new Tuple(0, 'Y', 1)); - ASpec.Add(new Tuple(1, 'Y', 1)); - ASpec.Add(new Tuple(1, 'B', 1)); - ASpec.Add(new Tuple(1, 'R', 1)); - ASpec.Add(new Tuple(1, 'L', 1)); - ASpec.Add(new Tuple(1, 'A', 1)); - ASpec.Add(new Tuple(0, 'P', 0)); - ASpec.Add(new Tuple(1, 'P', 1)); - - // initial: 1, final: 0 - BSpec = new List>(); - BSpec.Add(new Tuple(1, 'Y', 0)); - BSpec.Add(new Tuple(1, 'Y', 1)); - BSpec.Add(new Tuple(1, 'B', 1)); - BSpec.Add(new Tuple(1, 'R', 1)); - BSpec.Add(new Tuple(1, 'L', 1)); - BSpec.Add(new Tuple(1, 'A', 1)); - BSpec.Add(new Tuple(0, 'P', 0)); - BSpec.Add(new Tuple(1, 'P', 1)); - - // initial: {0, 1}, final: {0, 1} - CSpec = new List>(); - CSpec.Add(new Tuple(0, 'B', 0)); - CSpec.Add(new Tuple(0, 'R', 0)); - CSpec.Add(new Tuple(0, 'Y', 0)); - CSpec.Add(new Tuple(0, 'B', 1)); - CSpec.Add(new Tuple(0, 'R', 1)); - CSpec.Add(new Tuple(0, 'L', 1)); - CSpec.Add(new Tuple(0, 'A', 1)); - CSpec.Add(new Tuple(1, 'B', 1)); - CSpec.Add(new Tuple(1, 'L', 1)); - CSpec.Add(new Tuple(1, 'Y', 0)); - CSpec.Add(new Tuple(0, 'P', 0)); - CSpec.Add(new Tuple(1, 'P', 1)); - } - - private void IsYieldTypeSafe() - { - List> implEdges = new List>(); - foreach (Tuple e in edgeLabels.Keys) - { - implEdges.Add(new Tuple(e.Item1, edgeLabels[e], e.Item2)); - } - //Console.WriteLine(PrintGraph(impl, implEdges, initialState, finalStates)); - ASpecCheck(implEdges); - BSpecCheck(implEdges); - CSpecCheck(implEdges); - } - - private void ASpecCheck(List> implEdges) - { - Dictionary> initialConstraints = new Dictionary>(); - initialConstraints[initialState] = new HashSet(new int[] { 0 }); - foreach (var finalState in finalStates) - { - initialConstraints[finalState] = new HashSet(new int[] { 1 }); - } - SimulationRelation x = new SimulationRelation(implEdges, ASpec, initialConstraints); - Dictionary> simulationRelation = x.ComputeSimulationRelation(); - if (simulationRelation[initialState].Count == 0) - { - moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check A at layer {1}. An action must be preceded by a yield.\n", impl.Name, currLayerNum)); - } - } - - private void BSpecCheck(List> implEdges) - { - Dictionary> initialConstraints = new Dictionary>(); - initialConstraints[initialState] = new HashSet(new int[] { 1 }); - foreach (var finalState in finalStates) - { - initialConstraints[finalState] = new HashSet(new int[] { 0 }); - } - SimulationRelation x = new SimulationRelation(implEdges, BSpec, initialConstraints); - Dictionary> simulationRelation = x.ComputeSimulationRelation(); - if (simulationRelation[initialState].Count == 0) - { - moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check B at layer {1}. An action must be succeeded by a yield.\n", impl.Name, currLayerNum)); - } - } - - private void CSpecCheck(List> implEdges) - { - Dictionary> initialConstraints = new Dictionary>(); - foreach (Block block in loopHeaders) - { - if (!IsTerminatingLoopHeader(block)) - { - initialConstraints[absyToNode[block]] = new HashSet(new int[] { 0 }); - } - } - SimulationRelation x = new SimulationRelation(implEdges, CSpec, initialConstraints); - Dictionary> simulationRelation = x.ComputeSimulationRelation(); - if (simulationRelation[initialState].Count == 0) - { - moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check C at layer {1}. Transactions must be separated by a yield.\n", impl.Name, currLayerNum)); - } - } - - private bool IsTerminatingLoopHeader(Block block) - { - foreach (Cmd cmd in block.Cmds) - { - AssertCmd assertCmd = cmd as AssertCmd; - if (assertCmd != null && QKeyValue.FindBoolAttribute(assertCmd.Attributes, "terminates") && moverTypeChecker.absyToLayerNums[assertCmd].Contains(currLayerNum)) - { - return true; - } - } - return false; - } - - public static void PerformYieldSafeCheck(MoverTypeChecker moverTypeChecker) - { - foreach (var impl in moverTypeChecker.program.Implementations) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) continue; - impl.PruneUnreachableBlocks(); - Graph implGraph = Program.GraphFromImpl(impl); - implGraph.ComputeLoops(); - int specLayerNum = moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum; - foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum })) - { - if (layerNum > specLayerNum) continue; - YieldTypeChecker executor = new YieldTypeChecker(moverTypeChecker, impl, layerNum, implGraph.Headers); - } - } - } - - int stateCounter; - MoverTypeChecker moverTypeChecker; - Implementation impl; - int currLayerNum; - Dictionary absyToNode; - Dictionary nodeToAbsy; - int initialState; - HashSet finalStates; - Dictionary, int> edgeLabels; - IEnumerable loopHeaders; - - private YieldTypeChecker(MoverTypeChecker moverTypeChecker, Implementation impl, int currLayerNum, IEnumerable loopHeaders) - { - this.moverTypeChecker = moverTypeChecker; - this.impl = impl; - this.currLayerNum = currLayerNum; - this.loopHeaders = loopHeaders; - this.stateCounter = 0; - this.absyToNode = new Dictionary(); - this.initialState = 0; - this.finalStates = new HashSet(); - this.edgeLabels = new Dictionary, int>(); - - foreach (Block block in impl.Blocks) - { - absyToNode[block] = stateCounter; - stateCounter++; - foreach (Cmd cmd in block.Cmds) - { - absyToNode[cmd] = stateCounter; - stateCounter++; - } - absyToNode[block.TransferCmd] = stateCounter; - stateCounter++; - if (block.TransferCmd is ReturnCmd) - { - finalStates.Add(absyToNode[block.TransferCmd]); - } - } - foreach (Block block in impl.Blocks) - { - Absy blockEntry = block.Cmds.Count == 0 ? (Absy)block.TransferCmd : (Absy)block.Cmds[0]; - edgeLabels[new Tuple(absyToNode[block], absyToNode[blockEntry])] = 'P'; - - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - if (gotoCmd == null) continue; - foreach (Block successor in gotoCmd.labelTargets) - { - edgeLabels[new Tuple(absyToNode[gotoCmd], absyToNode[successor])] = 'P'; - } - } - - this.nodeToAbsy = new Dictionary(); - foreach (KeyValuePair state in absyToNode) - { - this.nodeToAbsy[state.Value] = state.Key; - } - - ComputeGraph(); - IsYieldTypeSafe(); - } - - private void ComputeGraph() - { - foreach (Block block in impl.Blocks) - { - for (int i = 0; i < block.Cmds.Count; i++) - { - Cmd cmd = block.Cmds[i]; - int curr = absyToNode[cmd]; - int next = (i + 1 == block.Cmds.Count) ? absyToNode[block.TransferCmd] : absyToNode[block.Cmds[i + 1]]; - Tuple edge = new Tuple(curr, next); - if (cmd is CallCmd) - { - CallCmd callCmd = cmd as CallCmd; - if (callCmd.IsAsync) - { - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; - if (currLayerNum <= actionInfo.createdAtLayerNum) - edgeLabels[edge] = 'L'; - else - edgeLabels[edge] = 'B'; - } - else if (!moverTypeChecker.procToActionInfo.ContainsKey(callCmd.Proc)) - { - edgeLabels[edge] = 'P'; - } - else - { - MoverType moverType; - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; - if (actionInfo.createdAtLayerNum >= currLayerNum) - { - moverType = MoverType.Top; - } - else - { - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo == null) - moverType = MoverType.Both; - else - moverType = atomicActionInfo.moverType; - } - switch (moverType) - { - case MoverType.Atomic: - edgeLabels[edge] = 'A'; - break; - case MoverType.Both: - edgeLabels[edge] = 'B'; - break; - case MoverType.Left: - edgeLabels[edge] = 'L'; - break; - case MoverType.Right: - edgeLabels[edge] = 'R'; - break; - case MoverType.Top: - edgeLabels[edge] = 'Y'; - break; - } - } - } - else if (cmd is ParCallCmd) - { - ParCallCmd parCallCmd = cmd as ParCallCmd; - bool isYield = false; - bool isRightMover = true; - bool isLeftMover = true; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - if (moverTypeChecker.procToActionInfo[callCmd.Proc].createdAtLayerNum >= currLayerNum) - { - isYield = true; - } - } - if (isYield) - { - edgeLabels[edge] = 'Y'; - } - else - { - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; - isRightMover = isRightMover && actionInfo.IsRightMover; - isLeftMover = isLeftMover && actionInfo.IsLeftMover; - } - if (isLeftMover && isRightMover) - { - edgeLabels[edge] = 'B'; - } - else if (isLeftMover) - { - edgeLabels[edge] = 'L'; - } - else if (isRightMover) - { - edgeLabels[edge] = 'R'; - } - else - { - Debug.Assert(parCallCmd.CallCmds.Count == 1); - edgeLabels[edge] = 'A'; - } - } - } - else if (cmd is YieldCmd) - { - edgeLabels[edge] = 'Y'; - } - else - { - edgeLabels[edge] = 'P'; - } - } - } - } - - private static string PrintGraph(Implementation impl, List> edges, int initialState, HashSet finalStates) - { - var s = new StringBuilder(); - s.AppendLine("\nImplementation " + impl.Proc.Name + " digraph G {"); - foreach (var e in edges) - { - string label = "P"; - switch (e.Item2) - { - case 'P': label = "P"; break; - case 'Y': label = "Y"; break; - case 'B': label = "B"; break; - case 'R': label = "R"; break; - case 'L': label = "L"; break; - case 'A': label = "A"; break; - default: Debug.Assert(false); break; - } - s.AppendLine(" \"" + e.Item1.ToString() + "\" -- " + label + " --> " + " \"" + e.Item3.ToString() + "\";"); - } - s.AppendLine("}"); - s.AppendLine("Initial state: " + initialState); - s.Append("Final states: "); - bool first = true; - foreach (int finalState in finalStates) - { - s.Append((first ? "" : ", ") + finalState); - first = false; - } - s.AppendLine(); - return s.ToString(); - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.AbstractInterpretation; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + class YieldTypeChecker + { + static List> ASpec; + static List> BSpec; + static List> CSpec; + static YieldTypeChecker() + { + // initial: 0, final: 1 + ASpec = new List>(); + ASpec.Add(new Tuple(0, 'Y', 1)); + ASpec.Add(new Tuple(1, 'Y', 1)); + ASpec.Add(new Tuple(1, 'B', 1)); + ASpec.Add(new Tuple(1, 'R', 1)); + ASpec.Add(new Tuple(1, 'L', 1)); + ASpec.Add(new Tuple(1, 'A', 1)); + ASpec.Add(new Tuple(0, 'P', 0)); + ASpec.Add(new Tuple(1, 'P', 1)); + + // initial: 1, final: 0 + BSpec = new List>(); + BSpec.Add(new Tuple(1, 'Y', 0)); + BSpec.Add(new Tuple(1, 'Y', 1)); + BSpec.Add(new Tuple(1, 'B', 1)); + BSpec.Add(new Tuple(1, 'R', 1)); + BSpec.Add(new Tuple(1, 'L', 1)); + BSpec.Add(new Tuple(1, 'A', 1)); + BSpec.Add(new Tuple(0, 'P', 0)); + BSpec.Add(new Tuple(1, 'P', 1)); + + // initial: {0, 1}, final: {0, 1} + CSpec = new List>(); + CSpec.Add(new Tuple(0, 'B', 0)); + CSpec.Add(new Tuple(0, 'R', 0)); + CSpec.Add(new Tuple(0, 'Y', 0)); + CSpec.Add(new Tuple(0, 'B', 1)); + CSpec.Add(new Tuple(0, 'R', 1)); + CSpec.Add(new Tuple(0, 'L', 1)); + CSpec.Add(new Tuple(0, 'A', 1)); + CSpec.Add(new Tuple(1, 'B', 1)); + CSpec.Add(new Tuple(1, 'L', 1)); + CSpec.Add(new Tuple(1, 'Y', 0)); + CSpec.Add(new Tuple(0, 'P', 0)); + CSpec.Add(new Tuple(1, 'P', 1)); + } + + private void IsYieldTypeSafe() + { + List> implEdges = new List>(); + foreach (Tuple e in edgeLabels.Keys) + { + implEdges.Add(new Tuple(e.Item1, edgeLabels[e], e.Item2)); + } + //Console.WriteLine(PrintGraph(impl, implEdges, initialState, finalStates)); + ASpecCheck(implEdges); + BSpecCheck(implEdges); + CSpecCheck(implEdges); + } + + private void ASpecCheck(List> implEdges) + { + Dictionary> initialConstraints = new Dictionary>(); + initialConstraints[initialState] = new HashSet(new int[] { 0 }); + foreach (var finalState in finalStates) + { + initialConstraints[finalState] = new HashSet(new int[] { 1 }); + } + SimulationRelation x = new SimulationRelation(implEdges, ASpec, initialConstraints); + Dictionary> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check A at layer {1}. An action must be preceded by a yield.\n", impl.Name, currLayerNum)); + } + } + + private void BSpecCheck(List> implEdges) + { + Dictionary> initialConstraints = new Dictionary>(); + initialConstraints[initialState] = new HashSet(new int[] { 1 }); + foreach (var finalState in finalStates) + { + initialConstraints[finalState] = new HashSet(new int[] { 0 }); + } + SimulationRelation x = new SimulationRelation(implEdges, BSpec, initialConstraints); + Dictionary> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check B at layer {1}. An action must be succeeded by a yield.\n", impl.Name, currLayerNum)); + } + } + + private void CSpecCheck(List> implEdges) + { + Dictionary> initialConstraints = new Dictionary>(); + foreach (Block block in loopHeaders) + { + if (!IsTerminatingLoopHeader(block)) + { + initialConstraints[absyToNode[block]] = new HashSet(new int[] { 0 }); + } + } + SimulationRelation x = new SimulationRelation(implEdges, CSpec, initialConstraints); + Dictionary> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check C at layer {1}. Transactions must be separated by a yield.\n", impl.Name, currLayerNum)); + } + } + + private bool IsTerminatingLoopHeader(Block block) + { + foreach (Cmd cmd in block.Cmds) + { + AssertCmd assertCmd = cmd as AssertCmd; + if (assertCmd != null && QKeyValue.FindBoolAttribute(assertCmd.Attributes, "terminates") && moverTypeChecker.absyToLayerNums[assertCmd].Contains(currLayerNum)) + { + return true; + } + } + return false; + } + + public static void PerformYieldSafeCheck(MoverTypeChecker moverTypeChecker) + { + foreach (var impl in moverTypeChecker.program.Implementations) + { + if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) continue; + impl.PruneUnreachableBlocks(); + Graph implGraph = Program.GraphFromImpl(impl); + implGraph.ComputeLoops(); + int specLayerNum = moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum; + foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum })) + { + if (layerNum > specLayerNum) continue; + YieldTypeChecker executor = new YieldTypeChecker(moverTypeChecker, impl, layerNum, implGraph.Headers); + } + } + } + + int stateCounter; + MoverTypeChecker moverTypeChecker; + Implementation impl; + int currLayerNum; + Dictionary absyToNode; + Dictionary nodeToAbsy; + int initialState; + HashSet finalStates; + Dictionary, int> edgeLabels; + IEnumerable loopHeaders; + + private YieldTypeChecker(MoverTypeChecker moverTypeChecker, Implementation impl, int currLayerNum, IEnumerable loopHeaders) + { + this.moverTypeChecker = moverTypeChecker; + this.impl = impl; + this.currLayerNum = currLayerNum; + this.loopHeaders = loopHeaders; + this.stateCounter = 0; + this.absyToNode = new Dictionary(); + this.initialState = 0; + this.finalStates = new HashSet(); + this.edgeLabels = new Dictionary, int>(); + + foreach (Block block in impl.Blocks) + { + absyToNode[block] = stateCounter; + stateCounter++; + foreach (Cmd cmd in block.Cmds) + { + absyToNode[cmd] = stateCounter; + stateCounter++; + } + absyToNode[block.TransferCmd] = stateCounter; + stateCounter++; + if (block.TransferCmd is ReturnCmd) + { + finalStates.Add(absyToNode[block.TransferCmd]); + } + } + foreach (Block block in impl.Blocks) + { + Absy blockEntry = block.Cmds.Count == 0 ? (Absy)block.TransferCmd : (Absy)block.Cmds[0]; + edgeLabels[new Tuple(absyToNode[block], absyToNode[blockEntry])] = 'P'; + + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + if (gotoCmd == null) continue; + foreach (Block successor in gotoCmd.labelTargets) + { + edgeLabels[new Tuple(absyToNode[gotoCmd], absyToNode[successor])] = 'P'; + } + } + + this.nodeToAbsy = new Dictionary(); + foreach (KeyValuePair state in absyToNode) + { + this.nodeToAbsy[state.Value] = state.Key; + } + + ComputeGraph(); + IsYieldTypeSafe(); + } + + private void ComputeGraph() + { + foreach (Block block in impl.Blocks) + { + for (int i = 0; i < block.Cmds.Count; i++) + { + Cmd cmd = block.Cmds[i]; + int curr = absyToNode[cmd]; + int next = (i + 1 == block.Cmds.Count) ? absyToNode[block.TransferCmd] : absyToNode[block.Cmds[i + 1]]; + Tuple edge = new Tuple(curr, next); + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (callCmd.IsAsync) + { + ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; + if (currLayerNum <= actionInfo.createdAtLayerNum) + edgeLabels[edge] = 'L'; + else + edgeLabels[edge] = 'B'; + } + else if (!moverTypeChecker.procToActionInfo.ContainsKey(callCmd.Proc)) + { + edgeLabels[edge] = 'P'; + } + else + { + MoverType moverType; + ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; + if (actionInfo.createdAtLayerNum >= currLayerNum) + { + moverType = MoverType.Top; + } + else + { + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo == null) + moverType = MoverType.Both; + else + moverType = atomicActionInfo.moverType; + } + switch (moverType) + { + case MoverType.Atomic: + edgeLabels[edge] = 'A'; + break; + case MoverType.Both: + edgeLabels[edge] = 'B'; + break; + case MoverType.Left: + edgeLabels[edge] = 'L'; + break; + case MoverType.Right: + edgeLabels[edge] = 'R'; + break; + case MoverType.Top: + edgeLabels[edge] = 'Y'; + break; + } + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = cmd as ParCallCmd; + bool isYield = false; + bool isRightMover = true; + bool isLeftMover = true; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + if (moverTypeChecker.procToActionInfo[callCmd.Proc].createdAtLayerNum >= currLayerNum) + { + isYield = true; + } + } + if (isYield) + { + edgeLabels[edge] = 'Y'; + } + else + { + int numAtomicActions = 0; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc]; + isRightMover = isRightMover && actionInfo.IsRightMover; + isLeftMover = isLeftMover && actionInfo.IsLeftMover; + if (actionInfo is AtomicActionInfo) + { + numAtomicActions++; + } + } + if (isLeftMover && isRightMover) + { + edgeLabels[edge] = 'B'; + } + else if (isLeftMover) + { + edgeLabels[edge] = 'L'; + } + else if (isRightMover) + { + edgeLabels[edge] = 'R'; + } + else + { + Debug.Assert(numAtomicActions == 1); + edgeLabels[edge] = 'A'; + } + } + } + else if (cmd is YieldCmd) + { + edgeLabels[edge] = 'Y'; + } + else + { + edgeLabels[edge] = 'P'; + } + } + } + } + + private static string PrintGraph(Implementation impl, List> edges, int initialState, HashSet finalStates) + { + var s = new StringBuilder(); + s.AppendLine("\nImplementation " + impl.Proc.Name + " digraph G {"); + foreach (var e in edges) + { + string label = "P"; + switch (e.Item2) + { + case 'P': label = "P"; break; + case 'Y': label = "Y"; break; + case 'B': label = "B"; break; + case 'R': label = "R"; break; + case 'L': label = "L"; break; + case 'A': label = "A"; break; + default: Debug.Assert(false); break; + } + s.AppendLine(" \"" + e.Item1.ToString() + "\" -- " + label + " --> " + " \"" + e.Item3.ToString() + "\";"); + } + s.AppendLine("}"); + s.AppendLine("Initial state: " + initialState); + s.Append("Final states: "); + bool first = true; + foreach (int finalState in finalStates) + { + s.Append((first ? "" : ", ") + finalState); + first = false; + } + s.AppendLine(); + return s.ToString(); + } + } +} diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs index 7776f4de..9fda36e7 100644 --- a/Source/Provers/SMTLib/SMTLibProcess.cs +++ b/Source/Provers/SMTLib/SMTLibProcess.cs @@ -1,397 +1,397 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Diagnostics.Contracts; - -namespace Microsoft.Boogie.SMTLib -{ - public class SMTLibProcess - { - readonly Process prover; - readonly Inspector inspector; - readonly SMTLibProverOptions options; - readonly Queue proverOutput = new Queue(); - readonly Queue proverErrors = new Queue(); - readonly TextWriter toProver; - readonly int smtProcessId; - static int smtProcessIdSeq = 0; - ConsoleCancelEventHandler cancelEvent; - public bool NeedsRestart; - - public static ProcessStartInfo ComputerProcessStartInfo(string executable, string options) - { - return new ProcessStartInfo(executable, options) - { - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardInput = true, - RedirectStandardOutput = true, - RedirectStandardError = true - }; - } - - public SMTLibProcess(ProcessStartInfo psi, SMTLibProverOptions options) - { - this.options = options; - this.smtProcessId = smtProcessIdSeq++; - - if (options.Inspector != null) { - this.inspector = new Inspector(options); - } - - foreach (var arg in options.SolverArguments) - psi.Arguments += " " + arg; - - if (cancelEvent == null && CommandLineOptions.Clo.RunningBoogieFromCommandLine) { - cancelEvent = new ConsoleCancelEventHandler(ControlCHandler); - Console.CancelKeyPress += cancelEvent; - } - - if (options.Verbosity >= 1) { - Console.WriteLine("[SMT-{0}] Starting {1} {2}", smtProcessId, psi.FileName, psi.Arguments); - } - - - try { - prover = new Process(); - prover.StartInfo = psi; - prover.ErrorDataReceived += prover_ErrorDataReceived; - prover.OutputDataReceived += prover_OutputDataReceived; - prover.Start(); - toProver = prover.StandardInput; - prover.BeginErrorReadLine(); - prover.BeginOutputReadLine(); - } catch (System.ComponentModel.Win32Exception e) { - throw new ProverException(string.Format("Unable to start the process {0}: {1}", psi.FileName, e.Message)); - } - } - - [NoDefaultContract] // important, since we have no idea what state the object might be in when this handler is invoked - void ControlCHandler(object o, ConsoleCancelEventArgs a) - { - if (prover != null) { - TerminateProver(); - } - } - - private void TerminateProver(Int32 timeout = 2000) { - try { - // Let the prover know that we're done sending input. - prover.StandardInput.Close(); - - // Give it a chance to exit cleanly (e.g. to flush buffers) - if (!prover.WaitForExit(timeout)) { - prover.Kill(); - } - } catch { /* Swallow errors */ } - } - - public void Send(string cmd) - { - if (options.Verbosity >= 2) { - var log = cmd; - if (log.Length > 50) - log = log.Substring(0, 50) + "..."; - log = log.Replace("\r", "").Replace("\n", " "); - Console.WriteLine("[SMT-INP-{0}] {1}", smtProcessId, log); - } - toProver.WriteLine(cmd); - } - - // this is less than perfect; (echo ...) would be better - public void Ping() - { - Send("(get-info :name)"); - } - - public bool IsPong(SExpr sx) - { - return sx != null && sx.Name == ":name"; - } - - public void PingPong() - { - Ping(); - while (true) { - var sx = GetProverResponse(); - if (sx == null) { - this.NeedsRestart = true; - HandleError("Prover died"); - return; - } - - if (IsPong(sx)) - return; - else - HandleError("Invalid PING response from the prover: " + sx.ToString()); - } - } - - internal Inspector Inspector - { - get { return inspector; } - } - - public SExpr GetProverResponse() - { - toProver.Flush(); - - while (true) { - var exprs = ParseSExprs(true).ToArray(); - Contract.Assert(exprs.Length <= 1); - if (exprs.Length == 0) - return null; - var resp = exprs[0]; - if (resp.Name == "error") { - if (resp.Arguments.Length == 1 && resp.Arguments[0].IsId) - HandleError(resp.Arguments[0].Name); - else - HandleError(resp.ToString()); - } else if (resp.Name == "progress") { - if (inspector != null) { - var sb = new StringBuilder(); - foreach (var a in resp.Arguments) { - if (a.Name == "labels") { - sb.Append("STATS LABELS"); - foreach (var x in a.Arguments) - sb.Append(" ").Append(x.Name); - } else if (a.Name.StartsWith(":")) { - sb.Append("STATS NAMED_VALUES ").Append(a.Name); - foreach (var x in a.Arguments) - sb.Append(" ").Append(x.Name); - } else { - continue; - } - inspector.StatsLine(sb.ToString()); - sb.Clear(); - } - } - } else if (resp.Name == "unsupported") { - // Skip -- this may be a benign "unsupported" from a previous command. - // Of course, this is suboptimal. We should really be using - // print-success to identify the errant command and determine whether - // the response is benign. - } else { - return resp; - } - } - } - - public static System.TimeSpan TotalUserTime = System.TimeSpan.Zero; - - public void Close() - { - TotalUserTime += prover.UserProcessorTime; - TerminateProver(); - DisposeProver(); - } - - public event Action ErrorHandler; - int errorCnt; - - private void HandleError(string msg) - { - if (options.Verbosity >= 2) - Console.WriteLine("[SMT-ERR-{0}] Handling error: {1}", smtProcessId, msg); - if (ErrorHandler != null) - ErrorHandler(msg); - } - - #region SExpr parsing - int linePos; - string currLine; - char SkipWs() - { - while (true) { - if (currLine == null) { - currLine = ReadProver(); - if (currLine == null) - return '\0'; - } - - - while (linePos < currLine.Length && char.IsWhiteSpace(currLine[linePos])) - linePos++; - - if (linePos < currLine.Length && currLine[linePos] != ';') - return currLine[linePos]; - else { - currLine = null; - linePos = 0; - } - } - } - - void Shift() - { - linePos++; - } - - string ParseId() - { - var sb = new StringBuilder(); - - var beg = SkipWs(); - - var quoted = beg == '"' || beg == '|'; - if (quoted) - Shift(); - while (true) { - if (linePos >= currLine.Length) { - if (quoted) { - sb.Append("\n"); - currLine = ReadProver(); - linePos = 0; - if (currLine == null) - break; - } else break; - } - - var c = currLine[linePos++]; - if (quoted && c == beg) - break; - if (!quoted && (char.IsWhiteSpace(c) || c == '(' || c == ')')) { - linePos--; - break; - } - if (quoted && c == '\\' && linePos < currLine.Length && currLine[linePos] == '"') { - sb.Append('"'); - linePos++; - continue; - } - sb.Append(c); - } - - return sb.ToString(); - } - - void ParseError(string msg) - { - HandleError("Error parsing prover output: " + msg); - } - - IEnumerable ParseSExprs(bool top) - { - while (true) { - var c = SkipWs(); - if (c == '\0') - break; - - if (c == ')') { - if (top) - ParseError("stray ')'"); - break; - } - - string id; - - if (c == '(') { - Shift(); - c = SkipWs(); - if (c == '\0') { - ParseError("expecting something after '('"); - break; - } else if (c == '(') { - id = ""; - } else { - id = ParseId(); - } - - var args = ParseSExprs(false).ToArray(); - - c = SkipWs(); - if (c == ')') { - Shift(); - } else { - ParseError("unclosed '(" + id + "'"); - } - yield return new SExpr(id, args); - } else { - id = ParseId(); - yield return new SExpr(id); - } - - if (top) break; - } - } - #endregion - - #region handling input from the prover - string ReadProver() - { - string error = null; - while (true) { - if (error != null) { - HandleError(error); - errorCnt++; - error = null; - } - - lock (this) { - while (proverOutput.Count == 0 && proverErrors.Count == 0 && !prover.HasExited) { - Monitor.Wait(this, 100); - } - - if (proverErrors.Count > 0) { - error = proverErrors.Dequeue(); - continue; - } - - if (proverOutput.Count > 0) { - return proverOutput.Dequeue(); - } - - if (prover.HasExited) { - DisposeProver(); - return null; - } - } - } - } - - void DisposeProver() - { - if (cancelEvent != null) { - Console.CancelKeyPress -= cancelEvent; - cancelEvent = null; - } - } - - void prover_OutputDataReceived(object sender, DataReceivedEventArgs e) - { - lock (this) { - if (e.Data != null) { - if (options.Verbosity >= 2 || (options.Verbosity >= 1 && !e.Data.StartsWith("(:name "))) { - Console.WriteLine("[SMT-OUT-{0}] {1}", smtProcessId, e.Data); - } - proverOutput.Enqueue(e.Data); - Monitor.Pulse(this); - } - } - } - - void prover_ErrorDataReceived(object sender, DataReceivedEventArgs e) - { - lock (this) { - if (e.Data != null) { - if (options.Verbosity >= 1) - Console.WriteLine("[SMT-ERR-{0}] {1}", smtProcessId, e.Data); - proverErrors.Enqueue(e.Data); - Monitor.Pulse(this); - } - } - } - #endregion - } -} - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Diagnostics.Contracts; + +namespace Microsoft.Boogie.SMTLib +{ + public class SMTLibProcess + { + readonly Process prover; + readonly Inspector inspector; + readonly SMTLibProverOptions options; + readonly Queue proverOutput = new Queue(); + readonly Queue proverErrors = new Queue(); + readonly TextWriter toProver; + readonly int smtProcessId; + static int smtProcessIdSeq = 0; + ConsoleCancelEventHandler cancelEvent; + public bool NeedsRestart; + + public static ProcessStartInfo ComputerProcessStartInfo(string executable, string options) + { + return new ProcessStartInfo(executable, options) + { + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + } + + public SMTLibProcess(ProcessStartInfo psi, SMTLibProverOptions options) + { + this.options = options; + this.smtProcessId = smtProcessIdSeq++; + + if (options.Inspector != null) { + this.inspector = new Inspector(options); + } + + foreach (var arg in options.SolverArguments) + psi.Arguments += " " + arg; + + if (cancelEvent == null && CommandLineOptions.Clo.RunningBoogieFromCommandLine) { + cancelEvent = new ConsoleCancelEventHandler(ControlCHandler); + Console.CancelKeyPress += cancelEvent; + } + + if (options.Verbosity >= 1) { + Console.WriteLine("[SMT-{0}] Starting {1} {2}", smtProcessId, psi.FileName, psi.Arguments); + } + + + try { + prover = new Process(); + prover.StartInfo = psi; + prover.ErrorDataReceived += prover_ErrorDataReceived; + prover.OutputDataReceived += prover_OutputDataReceived; + prover.Start(); + toProver = prover.StandardInput; + prover.BeginErrorReadLine(); + prover.BeginOutputReadLine(); + } catch (System.ComponentModel.Win32Exception e) { + throw new ProverException(string.Format("Unable to start the process {0}: {1}", psi.FileName, e.Message)); + } + } + + [NoDefaultContract] // important, since we have no idea what state the object might be in when this handler is invoked + void ControlCHandler(object o, ConsoleCancelEventArgs a) + { + if (prover != null) { + TerminateProver(); + } + } + + private void TerminateProver(Int32 timeout = 2000) { + try { + // Let the prover know that we're done sending input. + prover.StandardInput.Close(); + + // Give it a chance to exit cleanly (e.g. to flush buffers) + if (!prover.WaitForExit(timeout)) { + prover.Kill(); + } + } catch { /* Swallow errors */ } + } + + public void Send(string cmd) + { + if (options.Verbosity >= 2) { + var log = cmd; + if (log.Length > 50) + log = log.Substring(0, 50) + "..."; + log = log.Replace("\r", "").Replace("\n", " "); + Console.WriteLine("[SMT-INP-{0}] {1}", smtProcessId, log); + } + toProver.WriteLine(cmd); + } + + // this is less than perfect; (echo ...) would be better + public void Ping() + { + Send("(get-info :name)"); + } + + public bool IsPong(SExpr sx) + { + return sx != null && sx.Name == ":name"; + } + + public void PingPong() + { + Ping(); + while (true) { + var sx = GetProverResponse(); + if (sx == null) { + this.NeedsRestart = true; + HandleError("Prover died"); + return; + } + + if (IsPong(sx)) + return; + else + HandleError("Invalid PING response from the prover: " + sx.ToString()); + } + } + + internal Inspector Inspector + { + get { return inspector; } + } + + public SExpr GetProverResponse() + { + toProver.Flush(); + + while (true) { + var exprs = ParseSExprs(true).ToArray(); + Contract.Assert(exprs.Length <= 1); + if (exprs.Length == 0) + return null; + var resp = exprs[0]; + if (resp.Name == "error") { + if (resp.Arguments.Length == 1 && resp.Arguments[0].IsId) + HandleError(resp.Arguments[0].Name); + else + HandleError(resp.ToString()); + } else if (resp.Name == "progress") { + if (inspector != null) { + var sb = new StringBuilder(); + foreach (var a in resp.Arguments) { + if (a.Name == "labels") { + sb.Append("STATS LABELS"); + foreach (var x in a.Arguments) + sb.Append(" ").Append(x.Name); + } else if (a.Name.StartsWith(":")) { + sb.Append("STATS NAMED_VALUES ").Append(a.Name); + foreach (var x in a.Arguments) + sb.Append(" ").Append(x.Name); + } else { + continue; + } + inspector.StatsLine(sb.ToString()); + sb.Clear(); + } + } + } else if (resp.Name == "unsupported") { + // Skip -- this may be a benign "unsupported" from a previous command. + // Of course, this is suboptimal. We should really be using + // print-success to identify the errant command and determine whether + // the response is benign. + } else { + return resp; + } + } + } + + public static System.TimeSpan TotalUserTime = System.TimeSpan.Zero; + + public void Close() + { + TotalUserTime += prover.UserProcessorTime; + TerminateProver(); + DisposeProver(); + } + + public event Action ErrorHandler; + int errorCnt; + + private void HandleError(string msg) + { + if (options.Verbosity >= 2) + Console.WriteLine("[SMT-ERR-{0}] Handling error: {1}", smtProcessId, msg); + if (ErrorHandler != null) + ErrorHandler(msg); + } + + #region SExpr parsing + int linePos; + string currLine; + char SkipWs() + { + while (true) { + if (currLine == null) { + currLine = ReadProver(); + if (currLine == null) + return '\0'; + } + + + while (linePos < currLine.Length && char.IsWhiteSpace(currLine[linePos])) + linePos++; + + if (linePos < currLine.Length && currLine[linePos] != ';') + return currLine[linePos]; + else { + currLine = null; + linePos = 0; + } + } + } + + void Shift() + { + linePos++; + } + + string ParseId() + { + var sb = new StringBuilder(); + + var beg = SkipWs(); + + var quoted = beg == '"' || beg == '|'; + if (quoted) + Shift(); + while (true) { + if (linePos >= currLine.Length) { + if (quoted) { + sb.Append("\n"); + currLine = ReadProver(); + linePos = 0; + if (currLine == null) + break; + } else break; + } + + var c = currLine[linePos++]; + if (quoted && c == beg) + break; + if (!quoted && (char.IsWhiteSpace(c) || c == '(' || c == ')')) { + linePos--; + break; + } + if (quoted && c == '\\' && linePos < currLine.Length && currLine[linePos] == '"') { + sb.Append('"'); + linePos++; + continue; + } + sb.Append(c); + } + + return sb.ToString(); + } + + void ParseError(string msg) + { + HandleError("Error parsing prover output: " + msg); + } + + IEnumerable ParseSExprs(bool top) + { + while (true) { + var c = SkipWs(); + if (c == '\0') + break; + + if (c == ')') { + if (top) + ParseError("stray ')'"); + break; + } + + string id; + + if (c == '(') { + Shift(); + c = SkipWs(); + if (c == '\0') { + ParseError("expecting something after '('"); + break; + } else if (c == '(') { + id = ""; + } else { + id = ParseId(); + } + + var args = ParseSExprs(false).ToArray(); + + c = SkipWs(); + if (c == ')') { + Shift(); + } else { + ParseError("unclosed '(" + id + "'"); + } + yield return new SExpr(id, args); + } else { + id = ParseId(); + yield return new SExpr(id); + } + + if (top) break; + } + } + #endregion + + #region handling input from the prover + string ReadProver() + { + string error = null; + while (true) { + if (error != null) { + HandleError(error); + errorCnt++; + error = null; + } + + lock (this) { + while (proverOutput.Count == 0 && proverErrors.Count == 0 && !prover.HasExited) { + Monitor.Wait(this, 100); + } + + if (proverErrors.Count > 0) { + error = proverErrors.Dequeue(); + continue; + } + + if (proverOutput.Count > 0) { + return proverOutput.Dequeue(); + } + + if (prover.HasExited) { + DisposeProver(); + return null; + } + } + } + } + + void DisposeProver() + { + if (cancelEvent != null) { + Console.CancelKeyPress -= cancelEvent; + cancelEvent = null; + } + } + + void prover_OutputDataReceived(object sender, DataReceivedEventArgs e) + { + lock (this) { + if (e.Data != null) { + if (options.Verbosity >= 2 || (options.Verbosity >= 1 && !e.Data.StartsWith("(:name "))) { + Console.WriteLine("[SMT-OUT-{0}] {1}", smtProcessId, e.Data); + } + proverOutput.Enqueue(e.Data); + Monitor.Pulse(this); + } + } + } + + void prover_ErrorDataReceived(object sender, DataReceivedEventArgs e) + { + lock (this) { + if (e.Data != null) { + if (options.Verbosity >= 1) + Console.WriteLine("[SMT-ERR-{0}] {1}", smtProcessId, e.Data); + proverErrors.Enqueue(e.Data); + Monitor.Pulse(this); + } + } + } + #endregion + } +} + diff --git a/Test/civl/chris3.bpl b/Test/civl/chris3.bpl new file mode 100644 index 00000000..5cbc000a --- /dev/null +++ b/Test/civl/chris3.bpl @@ -0,0 +1,19 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure{:yields}{:layer 94,94} H() +{ + yield; +} + +procedure{:yields}{:layer 94,95} A() + ensures{:atomic} |{ A: return true; }|; +{ + yield; +} + +procedure{:yields}{:layer 95,95} P() +{ + yield; + par A() | H(); + yield; +} diff --git a/Test/civl/chris3.bpl.expect b/Test/civl/chris3.bpl.expect new file mode 100644 index 00000000..c8b2ab00 --- /dev/null +++ b/Test/civl/chris3.bpl.expect @@ -0,0 +1,3 @@ +chris3.bpl(3,33): Error: Creation layer number must be less than the available upto layer number +chris3.bpl(14,33): Error: Creation layer number must be less than the available upto layer number +2 type checking errors detected in chris3.bpl -- cgit v1.2.3 From 56916c9d12f608dc580f4da03ef3dcbe35f42ef8 Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 10 Jun 2015 11:18:49 -0700 Subject: relaxed the check for created and hidden layers for skip actions --- Source/Concurrency/TypeCheck.cs | 20 ++++++++++++++------ Test/civl/chris3.bpl.expect | 5 ++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index 793012e6..542d3515 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -388,11 +388,6 @@ namespace Microsoft.Boogie Error(proc, "Incorrect number of layers"); continue; } - if (availableUptoLayerNum <= createdAtLayerNum) - { - Error(proc, "Creation layer number must be less than the available upto layer number"); - continue; - } foreach (Ensures e in proc.Ensures) { MoverType moverType = GetMoverType(e); @@ -408,6 +403,11 @@ namespace Microsoft.Boogie Error(proc, "A procedure can have at most one atomic action"); continue; } + if (availableUptoLayerNum <= createdAtLayerNum) + { + Error(proc, "Creation layer number must be less than the available upto layer number"); + continue; + } minLayerNum = int.MaxValue; maxLayerNum = -1; @@ -432,7 +432,15 @@ namespace Microsoft.Boogie if (errorCount > 0) continue; if (!procToActionInfo.ContainsKey(proc)) { - procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); + if (availableUptoLayerNum < createdAtLayerNum) + { + Error(proc, "Creation layer number must be no more than the available upto layer number"); + continue; + } + else + { + procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); + } } } if (errorCount > 0) return; diff --git a/Test/civl/chris3.bpl.expect b/Test/civl/chris3.bpl.expect index c8b2ab00..b415d3b9 100644 --- a/Test/civl/chris3.bpl.expect +++ b/Test/civl/chris3.bpl.expect @@ -1,3 +1,2 @@ -chris3.bpl(3,33): Error: Creation layer number must be less than the available upto layer number -chris3.bpl(14,33): Error: Creation layer number must be less than the available upto layer number -2 type checking errors detected in chris3.bpl +chris3.bpl(17,2): Error: The callee is not available in the caller procedure +1 type checking errors detected in chris3.bpl -- cgit v1.2.3 From 68fd205cdef86b38365f39c4e9157c8964b3568a Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 12 Jun 2015 00:43:41 +0200 Subject: Fix minor issue with diagnosing timeouts. --- Source/Provers/SMTLib/ProverInterface.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index c6c04b89..7e7f0cf6 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1317,7 +1317,9 @@ namespace Microsoft.Boogie.SMTLib } // TODO(wuestholz): Try out different ways for splitting up the work (e.g., randomly). - var split = new SortedSet(unverified.Where((val, idx) => idx < ((rem - 1) / frac + 1))); + var cnt = Math.Max(1, rem / frac); + // It seems like assertions later in the control flow have smaller indexes. + var split = new SortedSet(unverified.Where((val, idx) => (rem - idx - 1) < cnt)); Contract.Assert(0 < split.Count); var splitRes = CheckSplit(split, ref popLater, timeLimitPerAssertion, timeLimitPerAssertion, ref queries); if (splitRes == Outcome.Valid) @@ -1332,11 +1334,11 @@ namespace Microsoft.Boogie.SMTLib } else if (splitRes == Outcome.TimeOut) { - if (1 < frac && frac <= (rem / 4)) + if (2 <= frac && (4 <= (rem / frac))) { frac *= 4; } - else if (frac <= (rem / 2)) + else if (2 <= (rem / frac)) { frac *= 2; } -- cgit v1.2.3 From abd4a52488edea217b44419d43d4ca42abea9006 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 12 Jun 2015 01:04:27 +0200 Subject: Fix issue in checksum computation for lambda expressions. --- Source/Core/LambdaHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/LambdaHelper.cs b/Source/Core/LambdaHelper.cs index d07eaac6..0d115777 100644 --- a/Source/Core/LambdaHelper.cs +++ b/Source/Core/LambdaHelper.cs @@ -105,7 +105,7 @@ namespace Microsoft.Boogie { if (0 < CommandLineOptions.Clo.VerifySnapshots && QKeyValue.FindStringAttribute(lambdaAttrs, "checksum") == null) { // Attach a dummy checksum to avoid issues in the dependency analysis. - var checksumAttr = new QKeyValue(lambda.tok, "checksum", new List { "stable" }, null); + var checksumAttr = new QKeyValue(lambda.tok, "checksum", new List { "lambda expression" }, null); if (lambdaAttrs == null) { lambdaAttrs = checksumAttr; @@ -256,4 +256,4 @@ namespace Microsoft.Boogie { } } -} // end namespace \ No newline at end of file +} // end namespace -- cgit v1.2.3 From 0658816bbe2ea4be8785b52958a65b55c6a845a5 Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 12 Jun 2015 01:26:06 +0200 Subject: Add a test case. --- Test/snapshots/Snapshots36.v0.bpl | 14 ++++++++++++++ Test/snapshots/Snapshots36.v1.bpl | 14 ++++++++++++++ Test/snapshots/runtest.snapshot | 2 +- Test/snapshots/runtest.snapshot.expect | 9 +++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Test/snapshots/Snapshots36.v0.bpl create mode 100644 Test/snapshots/Snapshots36.v1.bpl diff --git a/Test/snapshots/Snapshots36.v0.bpl b/Test/snapshots/Snapshots36.v0.bpl new file mode 100644 index 00000000..9417af97 --- /dev/null +++ b/Test/snapshots/Snapshots36.v0.bpl @@ -0,0 +1,14 @@ +function {:checksum "2"} F() : bool +{ + true +} + +procedure {:checksum "0"} P(b: bool); + +implementation {:id "P"} {:checksum "1"} P(p: bool) +{ + var l: [int]bool; + + l := (lambda n: int :: F()); + assert l[0]; +} diff --git a/Test/snapshots/Snapshots36.v1.bpl b/Test/snapshots/Snapshots36.v1.bpl new file mode 100644 index 00000000..317182a5 --- /dev/null +++ b/Test/snapshots/Snapshots36.v1.bpl @@ -0,0 +1,14 @@ +function {:checksum "3"} F() : bool +{ + false +} + +procedure {:checksum "0"} P(b: bool); + +implementation {:id "P"} {:checksum "1"} P(p: bool) +{ + var l: [int]bool; + + l := (lambda n: int :: F()); + assert l[0]; +} diff --git a/Test/snapshots/runtest.snapshot b/Test/snapshots/runtest.snapshot index 01a231fe..608ac2d2 100644 --- a/Test/snapshots/runtest.snapshot +++ b/Test/snapshots/runtest.snapshot @@ -1,2 +1,2 @@ -// RUN: %boogie -errorTrace:0 -traceCaching:1 -verifySnapshots:2 -verifySeparately -noinfer Snapshots0.bpl Snapshots1.bpl Snapshots2.bpl Snapshots3.bpl Snapshots4.bpl Snapshots5.bpl Snapshots6.bpl Snapshots7.bpl Snapshots8.bpl Snapshots9.bpl Snapshots10.bpl Snapshots11.bpl Snapshots12.bpl Snapshots13.bpl Snapshots14.bpl Snapshots15.bpl Snapshots16.bpl Snapshots17.bpl Snapshots18.bpl Snapshots19.bpl Snapshots20.bpl Snapshots21.bpl Snapshots22.bpl Snapshots23.bpl Snapshots24.bpl Snapshots25.bpl Snapshots26.bpl Snapshots27.bpl Snapshots28.bpl Snapshots30.bpl Snapshots31.bpl Snapshots32.bpl Snapshots33.bpl Snapshots34.bpl Snapshots35.bpl > "%t" +// RUN: %boogie -errorTrace:0 -traceCaching:1 -verifySnapshots:2 -verifySeparately -noinfer Snapshots0.bpl Snapshots1.bpl Snapshots2.bpl Snapshots3.bpl Snapshots4.bpl Snapshots5.bpl Snapshots6.bpl Snapshots7.bpl Snapshots8.bpl Snapshots9.bpl Snapshots10.bpl Snapshots11.bpl Snapshots12.bpl Snapshots13.bpl Snapshots14.bpl Snapshots15.bpl Snapshots16.bpl Snapshots17.bpl Snapshots18.bpl Snapshots19.bpl Snapshots20.bpl Snapshots21.bpl Snapshots22.bpl Snapshots23.bpl Snapshots24.bpl Snapshots25.bpl Snapshots26.bpl Snapshots27.bpl Snapshots28.bpl Snapshots30.bpl Snapshots31.bpl Snapshots32.bpl Snapshots33.bpl Snapshots34.bpl Snapshots35.bpl Snapshots36.bpl > "%t" // RUN: %diff "%s.expect" "%t" diff --git a/Test/snapshots/runtest.snapshot.expect b/Test/snapshots/runtest.snapshot.expect index 637dd088..44ed6a3b 100644 --- a/Test/snapshots/runtest.snapshot.expect +++ b/Test/snapshots/runtest.snapshot.expect @@ -648,3 +648,12 @@ Processing command (at Snapshots35.v1.bpl(5,5)) assert p; Snapshots35.v1.bpl(5,5): Error BP5001: This assertion might not hold. Boogie program verifier finished with 0 verified, 1 error +Processing command (at Snapshots36.v0.bpl(13,5)) assert l[0]; + >>> DoNothingToAssert + +Boogie program verifier finished with 1 verified, 0 errors +Processing command (at Snapshots36.v1.bpl(13,5)) assert l[0]; + >>> DoNothingToAssert +Snapshots36.v1.bpl(13,5): Error BP5001: This assertion might not hold. + +Boogie program verifier finished with 0 verified, 1 error -- cgit v1.2.3 From 2920db784b61f02b6d68e249bc3b1c6d1cf26efd Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 12 Jun 2015 08:28:07 +0200 Subject: Fix issue with computation of statement checksums for lambda expressions. --- Source/Core/Absy.cs | 2 ++ Source/Core/AbsyExpr.cs | 10 +++++++++- Source/Core/LambdaHelper.cs | 1 + Test/snapshots/Snapshots37.v0.bpl | 9 +++++++++ Test/snapshots/Snapshots37.v1.bpl | 9 +++++++++ Test/snapshots/runtest.snapshot | 2 +- Test/snapshots/runtest.snapshot.expect | 9 +++++++++ 7 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 Test/snapshots/Snapshots37.v0.bpl create mode 100644 Test/snapshots/Snapshots37.v1.bpl diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs index 56bfc90f..0fedcd44 100644 --- a/Source/Core/Absy.cs +++ b/Source/Core/Absy.cs @@ -2630,6 +2630,8 @@ namespace Microsoft.Boogie { private bool neverTrigger; private bool neverTriggerComputed; + public string OriginalLambdaExprAsString; + public Function(IToken tok, string name, List args, Variable result) : this(tok, name, new List(), args, result, null) { Contract.Requires(result != null); diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index c19140d7..c816d7f2 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1983,7 +1983,15 @@ namespace Microsoft.Boogie { virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { //Contract.Requires(stream != null); //Contract.Requires(args != null); - this.name.Emit(stream, 0xF0, false); + + if (stream.UseForComputingChecksums && Func.OriginalLambdaExprAsString != null) + { + stream.Write(Func.OriginalLambdaExprAsString); + } + else + { + this.name.Emit(stream, 0xF0, false); + } if (stream.UseForComputingChecksums) { var c = Func.DependencyChecksum; diff --git a/Source/Core/LambdaHelper.cs b/Source/Core/LambdaHelper.cs index 0d115777..a2b0f143 100644 --- a/Source/Core/LambdaHelper.cs +++ b/Source/Core/LambdaHelper.cs @@ -176,6 +176,7 @@ namespace Microsoft.Boogie { } Function fn = new Function(tok, FreshLambdaFunctionName(), freshTypeVars, formals, res, "auto-generated lambda function", Substituter.Apply(Substituter.SubstitutionFromHashtable(substFnAttrs), lambdaAttrs)); + fn.OriginalLambdaExprAsString = lam_str; fcall = new FunctionCall(new IdentifierExpr(tok, fn.Name)); fcall.Func = fn; // resolve here diff --git a/Test/snapshots/Snapshots37.v0.bpl b/Test/snapshots/Snapshots37.v0.bpl new file mode 100644 index 00000000..f32b5c90 --- /dev/null +++ b/Test/snapshots/Snapshots37.v0.bpl @@ -0,0 +1,9 @@ +procedure {:checksum "0"} P(b: bool); + +implementation {:id "P"} {:checksum "1"} P(p: bool) +{ + var l: [int]bool; + + l := (lambda n: int :: true); + assert l[0]; +} diff --git a/Test/snapshots/Snapshots37.v1.bpl b/Test/snapshots/Snapshots37.v1.bpl new file mode 100644 index 00000000..689d2533 --- /dev/null +++ b/Test/snapshots/Snapshots37.v1.bpl @@ -0,0 +1,9 @@ +procedure {:checksum "0"} P(b: bool); + +implementation {:id "P"} {:checksum "2"} P(p: bool) +{ + var l: [int]bool; + + l := (lambda n: int :: false); + assert l[0]; +} diff --git a/Test/snapshots/runtest.snapshot b/Test/snapshots/runtest.snapshot index 608ac2d2..60b101aa 100644 --- a/Test/snapshots/runtest.snapshot +++ b/Test/snapshots/runtest.snapshot @@ -1,2 +1,2 @@ -// RUN: %boogie -errorTrace:0 -traceCaching:1 -verifySnapshots:2 -verifySeparately -noinfer Snapshots0.bpl Snapshots1.bpl Snapshots2.bpl Snapshots3.bpl Snapshots4.bpl Snapshots5.bpl Snapshots6.bpl Snapshots7.bpl Snapshots8.bpl Snapshots9.bpl Snapshots10.bpl Snapshots11.bpl Snapshots12.bpl Snapshots13.bpl Snapshots14.bpl Snapshots15.bpl Snapshots16.bpl Snapshots17.bpl Snapshots18.bpl Snapshots19.bpl Snapshots20.bpl Snapshots21.bpl Snapshots22.bpl Snapshots23.bpl Snapshots24.bpl Snapshots25.bpl Snapshots26.bpl Snapshots27.bpl Snapshots28.bpl Snapshots30.bpl Snapshots31.bpl Snapshots32.bpl Snapshots33.bpl Snapshots34.bpl Snapshots35.bpl Snapshots36.bpl > "%t" +// RUN: %boogie -errorTrace:0 -traceCaching:1 -verifySnapshots:2 -verifySeparately -noinfer Snapshots0.bpl Snapshots1.bpl Snapshots2.bpl Snapshots3.bpl Snapshots4.bpl Snapshots5.bpl Snapshots6.bpl Snapshots7.bpl Snapshots8.bpl Snapshots9.bpl Snapshots10.bpl Snapshots11.bpl Snapshots12.bpl Snapshots13.bpl Snapshots14.bpl Snapshots15.bpl Snapshots16.bpl Snapshots17.bpl Snapshots18.bpl Snapshots19.bpl Snapshots20.bpl Snapshots21.bpl Snapshots22.bpl Snapshots23.bpl Snapshots24.bpl Snapshots25.bpl Snapshots26.bpl Snapshots27.bpl Snapshots28.bpl Snapshots30.bpl Snapshots31.bpl Snapshots32.bpl Snapshots33.bpl Snapshots34.bpl Snapshots35.bpl Snapshots36.bpl Snapshots37.bpl > "%t" // RUN: %diff "%s.expect" "%t" diff --git a/Test/snapshots/runtest.snapshot.expect b/Test/snapshots/runtest.snapshot.expect index 44ed6a3b..bc96cc97 100644 --- a/Test/snapshots/runtest.snapshot.expect +++ b/Test/snapshots/runtest.snapshot.expect @@ -657,3 +657,12 @@ Processing command (at Snapshots36.v1.bpl(13,5)) assert l[0]; Snapshots36.v1.bpl(13,5): Error BP5001: This assertion might not hold. Boogie program verifier finished with 0 verified, 1 error +Processing command (at Snapshots37.v0.bpl(8,5)) assert l[0]; + >>> DoNothingToAssert + +Boogie program verifier finished with 1 verified, 0 errors +Processing command (at Snapshots37.v1.bpl(8,5)) assert l[0]; + >>> DoNothingToAssert +Snapshots37.v1.bpl(8,5): Error BP5001: This assertion might not hold. + +Boogie program verifier finished with 0 verified, 1 error -- cgit v1.2.3 From 0e851041485039a07684e0db5b584cd1237d3dfd Mon Sep 17 00:00:00 2001 From: Valentin Wüstholz Date: Fri, 12 Jun 2015 11:30:40 +0200 Subject: Minor changes --- Source/Core/CommandLineOptions.cs | 2 +- Source/Core/LambdaHelper.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index 1564b76b..b57ea02a 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -561,7 +561,7 @@ namespace Microsoft.Boogie { public bool UseLabels = true; public bool RunDiagnosticsOnTimeout = false; public bool TraceDiagnosticsOnTimeout = false; - public int TimeLimitPerAssertionInPercent = 20; + public int TimeLimitPerAssertionInPercent = 10; public bool SIBoolControlVC = false; public bool MonomorphicArrays { get { diff --git a/Source/Core/LambdaHelper.cs b/Source/Core/LambdaHelper.cs index a2b0f143..16e75760 100644 --- a/Source/Core/LambdaHelper.cs +++ b/Source/Core/LambdaHelper.cs @@ -67,7 +67,6 @@ namespace Microsoft.Boogie { string FreshLambdaFunctionName() { - // TODO(wuestholz): Should we use a counter per top-level declaration? return string.Format("lambda#{0}", lambdaid++); } -- cgit v1.2.3 From 4e9171d2b0dad5ea640ad781461a30910fbd73e5 Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Mon, 15 Jun 2015 14:19:46 -0700 Subject: adding z3name option --- Source/Core/CommandLineOptions.cs | 10 +++++++++- Source/Provers/SMTLib/Z3.cs | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index b57ea02a..309aab0e 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -484,6 +484,7 @@ namespace Microsoft.Boogie { public bool SimplifyLogFileAppend = false; public bool SoundnessSmokeTest = false; public string Z3ExecutablePath = null; + public string Z3ExecutableName = null; public string CVC4ExecutablePath = null; public int KInductionDepth = -1; @@ -1551,8 +1552,15 @@ namespace Microsoft.Boogie { Z3ExecutablePath = args[ps.i]; } return true; + // This sets name of z3 binary boogie binary directory, not path + case "z3name": + if (ps.ConfirmArgumentCount(1)) + { + Z3ExecutableName = args[ps.i]; + } + return true; - case "cvc4exe": + case "cvc4exe": if (ps.ConfirmArgumentCount(1)) { CVC4ExecutablePath = args[ps.i]; } diff --git a/Source/Provers/SMTLib/Z3.cs b/Source/Provers/SMTLib/Z3.cs index ffa4e0cb..bbc23917 100644 --- a/Source/Provers/SMTLib/Z3.cs +++ b/Source/Provers/SMTLib/Z3.cs @@ -52,7 +52,8 @@ namespace Microsoft.Boogie.SMTLib return; } - var proverExe = "z3.exe"; + var proverExe = CommandLineOptions.Clo.Z3ExecutableName; + proverExe = proverExe == null ? "z3.exe" : proverExe; if (_proverPath == null) { -- cgit v1.2.3 From e60e05a198970d64ea50b99bc605240d7a04e4cc Mon Sep 17 00:00:00 2001 From: qadeer Date: Mon, 15 Jun 2015 20:45:32 -0700 Subject: fixed bug reported by Chris --- Source/Core/DeadVarElim.cs | 3513 ++++++++++++++++++++++--------------------- Test/civl/chris4.bpl | 16 + Test/civl/chris4.bpl.expect | 5 + 3 files changed, 1782 insertions(+), 1752 deletions(-) create mode 100644 Test/civl/chris4.bpl create mode 100644 Test/civl/chris4.bpl.expect diff --git a/Source/Core/DeadVarElim.cs b/Source/Core/DeadVarElim.cs index 0feb5e35..fc39debb 100644 --- a/Source/Core/DeadVarElim.cs +++ b/Source/Core/DeadVarElim.cs @@ -1,1753 +1,1762 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Boogie.GraphUtil; -using System.Diagnostics.Contracts; - - -namespace Microsoft.Boogie { - public class UnusedVarEliminator : VariableCollector { - public static void Eliminate(Program program) { - Contract.Requires(program != null); - UnusedVarEliminator elim = new UnusedVarEliminator(); - elim.Visit(program); - } - - private UnusedVarEliminator() - : base() { - - } - - public override Implementation VisitImplementation(Implementation node) { - //Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - //Console.WriteLine("Procedure {0}", node.Name); - Implementation/*!*/ impl = base.VisitImplementation(node); - Contract.Assert(impl != null); - //Console.WriteLine("Old number of local variables = {0}", impl.LocVars.Length); - List/*!*/ vars = new List(); - foreach (Variable/*!*/ var in impl.LocVars) { - Contract.Assert(var != null); - if (_usedVars.Contains(var)) - vars.Add(var); - } - impl.LocVars = vars; - //Console.WriteLine("New number of local variables = {0}", impl.LocVars.Length); - //Console.WriteLine("---------------------------------"); - _usedVars.Clear(); - return impl; - } - } - - public class ModSetCollector : ReadOnlyVisitor { - private Procedure enclosingProc; - private Dictionary/*!*/>/*!*/ modSets; - private HashSet yieldingProcs; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullDictionaryAndValues(modSets)); - Contract.Invariant(Contract.ForAll(modSets.Values, v => cce.NonNullElements(v))); - } - - public ModSetCollector() { - modSets = new Dictionary/*!*/>(); - yieldingProcs = new HashSet(); - } - - private bool moreProcessingRequired; - - public void DoModSetAnalysis(Program program) { - Contract.Requires(program != null); - - if (CommandLineOptions.Clo.Trace) - { -// Console.WriteLine(); -// Console.WriteLine("Running modset analysis ..."); -// int procCount = 0; -// foreach (Declaration/*!*/ decl in program.TopLevelDeclarations) -// { -// Contract.Assert(decl != null); -// if (decl is Procedure) -// procCount++; -// } -// Console.WriteLine("Number of procedures = {0}", procCount);*/ - } - - HashSet implementedProcs = new HashSet(); - foreach (var impl in program.Implementations) { - if (impl.Proc != null) - implementedProcs.Add(impl.Proc); - } - foreach (var proc in program.Procedures) { - if (!implementedProcs.Contains(proc)) - { - enclosingProc = proc; - foreach (var expr in proc.Modifies) - { - Contract.Assert(expr != null); - ProcessVariable(expr.Decl); - } - enclosingProc = null; - } - else - { - modSets.Add(proc, new HashSet()); - } - } - - moreProcessingRequired = true; - while (moreProcessingRequired) { - moreProcessingRequired = false; - this.Visit(program); - } - - foreach (Procedure x in modSets.Keys) - { - x.Modifies = new List(); - foreach (Variable v in modSets[x]) - { - x.Modifies.Add(new IdentifierExpr(v.tok, v)); - } - } - foreach (Procedure x in yieldingProcs) - { - if (!QKeyValue.FindBoolAttribute(x.Attributes, "yields")) - { - x.AddAttribute("yields"); - } - } - -#if DEBUG_PRINT - Console.WriteLine("Number of procedures with nonempty modsets = {0}", modSets.Keys.Count); - foreach (Procedure/*!*/ x in modSets.Keys) { - Contract.Assert(x != null); - Console.Write("{0} : ", x.Name); - bool first = true; - foreach (Variable/*!*/ y in modSets[x]) { - Contract.Assert(y != null); - if (first) - first = false; - else - Console.Write(", "); - Console.Write("{0}", y.Name); - } - Console.WriteLine(""); - } -#endif - } - - public override Implementation VisitImplementation(Implementation node) { - //Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - enclosingProc = node.Proc; - Implementation/*!*/ ret = base.VisitImplementation(node); - Contract.Assert(ret != null); - enclosingProc = null; - - return ret; - } - public override YieldCmd VisitYieldCmd(YieldCmd node) - { - if (!yieldingProcs.Contains(enclosingProc)) - { - yieldingProcs.Add(enclosingProc); - moreProcessingRequired = true; - } - return base.VisitYieldCmd(node); - } - public override Cmd VisitAssignCmd(AssignCmd assignCmd) { - //Contract.Requires(assignCmd != null); - Contract.Ensures(Contract.Result() != null); - Cmd ret = base.VisitAssignCmd(assignCmd); - foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) { - Contract.Assert(lhs != null); - ProcessVariable(lhs.DeepAssignedVariable); - } - return ret; - } - public override Cmd VisitHavocCmd(HavocCmd havocCmd) { - //Contract.Requires(havocCmd != null); - Contract.Ensures(Contract.Result() != null); - Cmd ret = base.VisitHavocCmd(havocCmd); - foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { - Contract.Assert(expr != null); - ProcessVariable(expr.Decl); - } - return ret; - } - public override Cmd VisitCallCmd(CallCmd callCmd) { - //Contract.Requires(callCmd != null); - Contract.Ensures(Contract.Result() != null); - Cmd ret = base.VisitCallCmd(callCmd); - foreach (IdentifierExpr ie in callCmd.Outs) - { - if (ie != null) ProcessVariable(ie.Decl); - } - Procedure callee = callCmd.Proc; - if (callee == null) - return ret; - if (modSets.ContainsKey(callee)) { - foreach (Variable var in modSets[callee]) { - ProcessVariable(var); - } - } - if (!yieldingProcs.Contains(enclosingProc) && (yieldingProcs.Contains(callCmd.Proc) || callCmd.IsAsync)) - { - yieldingProcs.Add(enclosingProc); - moreProcessingRequired = true; - } - if (callCmd.IsAsync) - { - if (!yieldingProcs.Contains(callCmd.Proc)) - { - yieldingProcs.Add(callCmd.Proc); - moreProcessingRequired = true; - } - } - return ret; - } - public override Cmd VisitParCallCmd(ParCallCmd node) - { - //Contract.Requires(callCmd != null); - Contract.Ensures(Contract.Result() != null); - Cmd ret = base.VisitParCallCmd(node); - if (!yieldingProcs.Contains(enclosingProc)) - { - yieldingProcs.Add(enclosingProc); - moreProcessingRequired = true; - } - foreach (CallCmd callCmd in node.CallCmds) - { - if (!yieldingProcs.Contains(callCmd.Proc)) - { - yieldingProcs.Add(callCmd.Proc); - moreProcessingRequired = true; - } - } - return ret; - } - private void ProcessVariable(Variable var) { - Procedure/*!*/ localProc = cce.NonNull(enclosingProc); - if (var == null) - return; - if (!(var is GlobalVariable)) - return; - if (!modSets.ContainsKey(localProc)) { - modSets[localProc] = new HashSet(); - } - if (modSets[localProc].Contains(var)) - return; - moreProcessingRequired = true; - modSets[localProc].Add(var); - } - public override Expr VisitCodeExpr(CodeExpr node) { - // don't go into the code expression, since it can only modify variables local to the code expression, - // and the mod-set analysis is interested in global variables - return node; - } - } - - public class MutableVariableCollector : ReadOnlyVisitor - { - public HashSet UsedVariables = new HashSet(); - - public void AddUsedVariables(HashSet usedVariables) - { - Contract.Requires(usedVariables != null); - - foreach (var v in usedVariables) - { - UsedVariables.Add(v); - } - } - - public override Expr VisitIdentifierExpr(IdentifierExpr node) - { - Contract.Ensures(Contract.Result() != null); - - if (node.Decl != null && node.Decl.IsMutable) - { - UsedVariables.Add(node.Decl); - } - return base.VisitIdentifierExpr(node); - } - } - - public class VariableCollector : ReadOnlyVisitor { - protected HashSet/*!*/ _usedVars; - public IEnumerable/*!*/ usedVars - { - get - { - return _usedVars.AsEnumerable(); - } - } - - protected HashSet/*!*/ _oldVarsUsed; - public IEnumerable/*!*/ oldVarsUsed - { - get - { - return _oldVarsUsed.AsEnumerable(); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(_usedVars)); - Contract.Invariant(cce.NonNullElements(_oldVarsUsed)); - } - - int insideOldExpr; - - public VariableCollector() { - _usedVars = new System.Collections.Generic.HashSet(); - _oldVarsUsed = new System.Collections.Generic.HashSet(); - insideOldExpr = 0; - } - - public override Expr VisitOldExpr(OldExpr node) { - //Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - insideOldExpr++; - node.Expr = this.VisitExpr(node.Expr); - insideOldExpr--; - return node; - } - - public override Expr VisitIdentifierExpr(IdentifierExpr node) { - //Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - if (node.Decl != null) { - _usedVars.Add(node.Decl); - if (insideOldExpr > 0) { - _oldVarsUsed.Add(node.Decl); - } - } - return node; - } - } - - public class BlockCoalescer : ReadOnlyVisitor { - public static void CoalesceBlocks(Program program) { - Contract.Requires(program != null); - BlockCoalescer blockCoalescer = new BlockCoalescer(); - blockCoalescer.Visit(program); - } - - private static HashSet/*!*/ ComputeMultiPredecessorBlocks(Implementation/*!*/ impl) { - Contract.Requires(impl != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - HashSet visitedBlocks = new HashSet(); - HashSet multiPredBlocks = new HashSet(); - Stack dfsStack = new Stack(); - dfsStack.Push(impl.Blocks[0]); - while (dfsStack.Count > 0) { - Block/*!*/ b = dfsStack.Pop(); - Contract.Assert(b != null); - if (visitedBlocks.Contains(b)) { - multiPredBlocks.Add(b); - continue; - } - visitedBlocks.Add(b); - if (b.TransferCmd == null) - continue; - if (b.TransferCmd is ReturnCmd) - continue; - Contract.Assert(b.TransferCmd is GotoCmd); - GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; - if (gotoCmd.labelTargets == null) - continue; - foreach (Block/*!*/ succ in gotoCmd.labelTargets) { - Contract.Assert(succ != null); - dfsStack.Push(succ); - } - } - return multiPredBlocks; - } - - public override Implementation VisitImplementation(Implementation impl) { - //Contract.Requires(impl != null); - Contract.Ensures(Contract.Result() != null); - //Console.WriteLine("Procedure {0}", impl.Name); - //Console.WriteLine("Initial number of blocks = {0}", impl.Blocks.Count); - - HashSet multiPredBlocks = ComputeMultiPredecessorBlocks(impl); - Contract.Assert(cce.NonNullElements(multiPredBlocks)); - HashSet visitedBlocks = new HashSet(); - HashSet removedBlocks = new HashSet(); - Stack dfsStack = new Stack(); - dfsStack.Push(impl.Blocks[0]); - while (dfsStack.Count > 0) { - Block/*!*/ b = dfsStack.Pop(); - Contract.Assert(b != null); - if (visitedBlocks.Contains(b)) - continue; - visitedBlocks.Add(b); - if (b.TransferCmd == null) - continue; - if (b.TransferCmd is ReturnCmd) - continue; - Contract.Assert(b.TransferCmd is GotoCmd); - GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; - if (gotoCmd.labelTargets == null) - continue; - if (gotoCmd.labelTargets.Count == 1) { - Block/*!*/ succ = cce.NonNull(gotoCmd.labelTargets[0]); - if (!multiPredBlocks.Contains(succ)) { - foreach (Cmd/*!*/ cmd in succ.Cmds) { - Contract.Assert(cmd != null); - b.Cmds.Add(cmd); - } - b.TransferCmd = succ.TransferCmd; - if (!b.tok.IsValid && succ.tok.IsValid) { - b.tok = succ.tok; - b.Label = succ.Label; - } - removedBlocks.Add(succ); - dfsStack.Push(b); - visitedBlocks.Remove(b); - continue; - } - } - foreach (Block/*!*/ succ in gotoCmd.labelTargets) { - Contract.Assert(succ != null); - dfsStack.Push(succ); - } - } - - List newBlocks = new List(); - foreach (Block/*!*/ b in impl.Blocks) { - Contract.Assert(b != null); - if (visitedBlocks.Contains(b) && !removedBlocks.Contains(b)) { - newBlocks.Add(b); - } - } - impl.Blocks = newBlocks; - - // Console.WriteLine("Final number of blocks = {0}", impl.Blocks.Count); - return impl; - } - } - - public class LiveVariableAnalysis { - public static void ClearLiveVariables(Implementation impl) { - Contract.Requires(impl != null); - foreach (Block/*!*/ block in impl.Blocks) { - Contract.Assert(block != null); - block.liveVarsBefore = null; - } - } - - public static void ComputeLiveVariables(Implementation impl) { - Contract.Requires(impl != null); - Microsoft.Boogie.Helpers.ExtraTraceInformation("Starting live variable analysis"); - Graph dag = new Graph(); - dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph - foreach (Block b in impl.Blocks) { - GotoCmd gtc = b.TransferCmd as GotoCmd; - if (gtc != null) { - Contract.Assume(gtc.labelTargets != null); - foreach (Block/*!*/ dest in gtc.labelTargets) { - Contract.Assert(dest != null); - dag.AddEdge(dest, b); - } - } - } - - IEnumerable sortedNodes; - if (CommandLineOptions.Clo.ModifyTopologicalSorting) { - sortedNodes = dag.TopologicalSort(true); - } else { - sortedNodes = dag.TopologicalSort(); - } - foreach (Block/*!*/ block in sortedNodes) { - Contract.Assert(block != null); - HashSet/*!*/ liveVarsAfter = new HashSet(); - - // The injected assumption variables should always be considered to be live. - foreach (var v in impl.InjectedAssumptionVariables.Concat(impl.DoomedInjectedAssumptionVariables)) - { - liveVarsAfter.Add(v); - } - - if (block.TransferCmd is GotoCmd) { - GotoCmd gotoCmd = (GotoCmd)block.TransferCmd; - if (gotoCmd.labelTargets != null) { - foreach (Block/*!*/ succ in gotoCmd.labelTargets) { - Contract.Assert(succ != null); - Contract.Assert(succ.liveVarsBefore != null); - liveVarsAfter.UnionWith(succ.liveVarsBefore); - } - } - } - - List cmds = block.Cmds; - int len = cmds.Count; - for (int i = len - 1; i >= 0; i--) { - if (cmds[i] is CallCmd) { - Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc); - if (InterProcGenKill.HasSummary(proc.Name)) { - liveVarsAfter = - InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter); - continue; - } - } - Propagate(cmds[i], liveVarsAfter); - } - - block.liveVarsBefore = liveVarsAfter; - - } - } - - // perform in place update of liveSet - public static void Propagate(Cmd cmd, HashSet/*!*/ liveSet) { - Contract.Requires(cmd != null); - Contract.Requires(cce.NonNullElements(liveSet)); - if (cmd is AssignCmd) { - AssignCmd/*!*/ assignCmd = (AssignCmd)cce.NonNull(cmd); - // I must first iterate over all the targets and remove the live ones. - // After the removals are done, I must add the variables referred on - // the right side of the removed targets - - AssignCmd simpleAssignCmd = assignCmd.AsSimpleAssignCmd; - HashSet indexSet = new HashSet(); - int index = 0; - foreach (AssignLhs/*!*/ lhs in simpleAssignCmd.Lhss) { - Contract.Assert(lhs != null); - SimpleAssignLhs salhs = lhs as SimpleAssignLhs; - Contract.Assert(salhs != null); - Variable var = salhs.DeepAssignedVariable; - if (var != null && liveSet.Contains(var)) { - indexSet.Add(index); - liveSet.Remove(var); - } - index++; - } - index = 0; - foreach (Expr/*!*/ expr in simpleAssignCmd.Rhss) { - Contract.Assert(expr != null); - if (indexSet.Contains(index)) { - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(expr); - liveSet.UnionWith(collector.usedVars); - } - index++; - } - } else if (cmd is HavocCmd) { - HavocCmd/*!*/ havocCmd = (HavocCmd)cmd; - foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { - Contract.Assert(expr != null); - if (expr.Decl != null && !(QKeyValue.FindBoolAttribute(expr.Decl.Attributes, "assumption") && expr.Decl.Name.StartsWith("a##cached##"))) { - liveSet.Remove(expr.Decl); - } - } - } else if (cmd is PredicateCmd) { - Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd)); - PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd); - if (predicateCmd.Expr is LiteralExpr) { - LiteralExpr le = (LiteralExpr)predicateCmd.Expr; - if (le.IsFalse) { - liveSet.Clear(); - } - } else { - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(predicateCmd.Expr); - liveSet.UnionWith(collector.usedVars); - } - } else if (cmd is CommentCmd) { - // comments are just for debugging and don't affect verification - } else if (cmd is SugaredCmd) { - SugaredCmd/*!*/ sugCmd = (SugaredCmd)cce.NonNull(cmd); - Propagate(sugCmd.Desugaring, liveSet); - } else if (cmd is StateCmd) { - StateCmd/*!*/ stCmd = (StateCmd)cce.NonNull(cmd); - List/*!*/ cmds = cce.NonNull(stCmd.Cmds); - int len = cmds.Count; - for (int i = len - 1; i >= 0; i--) { - Propagate(cmds[i], liveSet); - } - foreach (Variable/*!*/ v in stCmd.Locals) { - Contract.Assert(v != null); - liveSet.Remove(v); - } - } else { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - } - } - - /* - // An idempotent semiring interface - abstract public class Weight { - abstract public Weight! one(); - abstract public Weight! zero(); - abstract public Weight! extend(Weight! w1, Weight! w2); - abstract public Weight! combine(Weight! w1, Weight! w2); - abstract public Weight! isEqual(Weight! w); - abstract public Weight! projectLocals() - } - */ - - // Weight domain for LiveVariableAnalysis (Gen/Kill) - - public class GenKillWeight { - // lambda S. (S - kill) union gen - HashSet/*!*/ gen; - HashSet/*!*/ kill; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(gen)); - Contract.Invariant(cce.NonNullElements(kill)); - Contract.Invariant(oneWeight != null); - Contract.Invariant(zeroWeight != null); - } - - bool isZero; - - public static GenKillWeight/*!*/ oneWeight = new GenKillWeight(new HashSet(), new HashSet()); - public static GenKillWeight/*!*/ zeroWeight = new GenKillWeight(); - - // initializes to zero - public GenKillWeight() { - this.isZero = true; - this.gen = new HashSet(); - this.kill = new HashSet(); - } - - public GenKillWeight(HashSet gen, HashSet kill) { - Contract.Requires(cce.NonNullElements(gen)); - Contract.Requires(cce.NonNullElements(kill)); - Contract.Assert(gen != null); - Contract.Assert(kill != null); - this.gen = gen; - this.kill = kill; - this.isZero = false; - } - - public static GenKillWeight one() { - Contract.Ensures(Contract.Result() != null); - return oneWeight; - } - - public static GenKillWeight zero() { - Contract.Ensures(Contract.Result() != null); - return zeroWeight; - } - - public static GenKillWeight extend(GenKillWeight w1, GenKillWeight w2) { - Contract.Requires(w2 != null); - Contract.Requires(w1 != null); - Contract.Ensures(Contract.Result() != null); - if (w1.isZero || w2.isZero) - return zero(); - - HashSet t = new HashSet(w2.gen); - t.ExceptWith(w1.kill); - HashSet g = new HashSet(w1.gen); - g.UnionWith(t); - HashSet k = new HashSet(w1.kill); - k.UnionWith(w2.kill); - return new GenKillWeight(g, k); - //return new GenKillWeight(w1.gen.Union(w2.gen.Difference(w1.kill)), w1.kill.Union(w2.kill)); - } - - public static GenKillWeight combine(GenKillWeight w1, GenKillWeight w2) { - Contract.Requires(w2 != null); - Contract.Requires(w1 != null); - Contract.Ensures(Contract.Result() != null); - if (w1.isZero) - return w2; - if (w2.isZero) - return w1; - - HashSet g = new HashSet(w1.gen); - g.UnionWith(w2.gen); - HashSet k = new HashSet(w1.kill); - k.IntersectWith(w2.kill); - return new GenKillWeight(g, k); - //return new GenKillWeight(w1.gen.Union(w2.gen), w1.kill.Intersection(w2.kill)); - } - - public static GenKillWeight projectLocals(GenKillWeight w) { - Contract.Requires(w != null); - Contract.Ensures(Contract.Result() != null); - HashSet gen = new HashSet(); - foreach (Variable v in w.gen) - { - if (isGlobal(v)) - gen.Add(v); - } - HashSet kill = new HashSet(); - foreach (Variable v in w.kill) - { - if (isGlobal(v)) - kill.Add(v); - } - - return new GenKillWeight(gen, kill); - } - - public static bool isEqual(GenKillWeight w1, GenKillWeight w2) { - Contract.Requires(w2 != null); - Contract.Requires(w1 != null); - if (w1.isZero) - return w2.isZero; - if (w2.isZero) - return w1.isZero; - - return (w1.gen.Equals(w2.gen) && w1.kill.Equals(w2.kill)); - } - - private static bool isGlobal(Variable v) { - Contract.Requires(v != null); - return (v is GlobalVariable); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format("({0},{1})", gen.ToString(), kill.ToString()); - } - - public HashSet/*!*/ getLiveVars() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return gen; - } - - public HashSet/*!*/ getLiveVars(HashSet/*!*/ lv) { - Contract.Requires(cce.NonNullElements(lv)); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - HashSet temp = new HashSet(lv); - temp.ExceptWith(kill); - temp.UnionWith(gen); - return temp; - } - - } - - public class ICFG { - public Graph/*!*/ graph; - // Map from procedure to the list of blocks that call that procedure - public Dictionary/*!*/>/*!*/ procsCalled; - public HashSet/*!*/ nodes; - public Dictionary/*!*/>/*!*/ succEdges; - public Dictionary/*!*/>/*!*/ predEdges; - private Dictionary/*!*/ priority; - - public HashSet/*!*/ srcNodes; - public HashSet/*!*/ exitNodes; - - public Dictionary/*!*/ weightBefore; - public Dictionary/*!*/ weightAfter; - public Dictionary/*!*/>/*!*/ liveVarsAfter; - public Dictionary/*!*/>/*!*/ liveVarsBefore; - - public GenKillWeight/*!*/ summary; - public Implementation/*!*/ impl; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(graph.Nodes)); - Contract.Invariant(cce.NonNullDictionaryAndValues(procsCalled)); - Contract.Invariant(cce.NonNullElements(nodes)); - Contract.Invariant(cce.NonNullDictionaryAndValues(succEdges)); - Contract.Invariant(cce.NonNullDictionaryAndValues(predEdges)); - Contract.Invariant(priority != null); - Contract.Invariant(cce.NonNullElements(srcNodes)); - Contract.Invariant(cce.NonNullElements(exitNodes)); - Contract.Invariant(cce.NonNullDictionaryAndValues(weightBefore)); - Contract.Invariant(cce.NonNullDictionaryAndValues(weightAfter)); - Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsAfter)); - Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsBefore)); - Contract.Invariant(summary != null); - Contract.Invariant(impl != null); - } - - - [NotDelayed] - public ICFG(Implementation impl) { - Contract.Requires(impl != null); - this.graph = new Graph(); - this.procsCalled = new Dictionary/*!*/>(); - this.nodes = new HashSet(); - this.succEdges = new Dictionary/*!*/>(); - this.predEdges = new Dictionary/*!*/>(); - - this.priority = new Dictionary(); - - this.srcNodes = new HashSet(); - this.exitNodes = new HashSet(); - - this.weightBefore = new Dictionary(); - this.weightAfter = new Dictionary(); - this.liveVarsAfter = new Dictionary/*!*/>(); - this.liveVarsBefore = new Dictionary/*!*/>(); - - summary = GenKillWeight.zero(); - this.impl = impl; - - Initialize(impl); - - } - - private void Initialize(Implementation impl) { - Contract.Requires(impl != null); - addSource(impl.Blocks[0]); - graph.AddSource(impl.Blocks[0]); - - foreach (Block/*!*/ b in impl.Blocks) { - Contract.Assert(b != null); - if (b.TransferCmd is ReturnCmd) { - exitNodes.Add(b); - } else { - GotoCmd gc = b.TransferCmd as GotoCmd; - Contract.Assert(gc != null); - Contract.Assert(gc.labelTargets != null); - foreach (Block/*!*/ t in gc.labelTargets) { - Contract.Assert(t != null); - addEdge(b, t); - graph.AddEdge(b, t); - } - } - - weightBefore[b] = GenKillWeight.zero(); - weightAfter[b] = GenKillWeight.zero(); - - foreach (Cmd/*!*/ c in b.Cmds) { - Contract.Assert(c != null); - if (c is CallCmd) { - CallCmd/*!*/ cc = cce.NonNull((CallCmd/*!*/)c); - Contract.Assert(cc.Proc != null); - string/*!*/ procName = cc.Proc.Name; - Contract.Assert(procName != null); - if (!procsCalled.ContainsKey(procName)) { - procsCalled.Add(procName, new List()); - } - procsCalled[procName].Add(b); - } - } - } - - List/*!*/ sortedNodes; - bool acyclic; - - graph.TarjanTopSort(out acyclic, out sortedNodes); - - if (!acyclic) { - Console.WriteLine("Warning: graph is not a dag"); - } - - int num = sortedNodes.Count; - foreach (Block/*!*/ b in sortedNodes) { - Contract.Assert(b != null); - priority.Add(b, num); - num--; - } - - } - - public int getPriority(Block b) { - Contract.Requires(b != null); - if (priority.ContainsKey(b)) - return priority[b]; - return Int32.MaxValue; - } - - private void addSource(Block b) { - Contract.Requires(b != null); - registerNode(b); - this.srcNodes.Add(b); - } - - private void addExit(Block b) { - Contract.Requires(b != null); - registerNode(b); - this.exitNodes.Add(b); - } - - private void registerNode(Block b) { - Contract.Requires(b != null); - if (!succEdges.ContainsKey(b)) { - succEdges.Add(b, new HashSet()); - } - - if (!predEdges.ContainsKey(b)) { - predEdges.Add(b, new HashSet()); - } - - nodes.Add(b); - } - - private void addEdge(Block src, Block tgt) { - Contract.Requires(tgt != null); - Contract.Requires(src != null); - registerNode(src); - registerNode(tgt); - - succEdges[src].Add(tgt); - predEdges[tgt].Add(src); - } - - - } - - // Interprocedural Gen/Kill Analysis - public class InterProcGenKill { - Program/*!*/ program; - Dictionary/*!*/ procICFG; - Dictionary/*!*/ name2Proc; - Dictionary/*!*/>/*!*/ callers; - Graph/*!*/ callGraph; - Dictionary/*!*/ procPriority; - int maxBlocksInProc; - - WorkList/*!*/ workList; - - Implementation/*!*/ mainImpl; - - static Dictionary/*!*/>/*!*/ varsLiveAtExit = new Dictionary/*!*/>(); - static Dictionary/*!*/>/*!*/ varsLiveAtEntry = new Dictionary/*!*/>(); - static Dictionary/*!*/ varsLiveSummary = new Dictionary(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(workList != null); - Contract.Invariant(mainImpl != null); - Contract.Invariant(program != null); - Contract.Invariant(cce.NonNullDictionaryAndValues(procICFG)); - Contract.Invariant(cce.NonNullDictionaryAndValues(name2Proc)); - Contract.Invariant(cce.NonNullDictionaryAndValues(callers) && - Contract.ForAll(callers.Values, v => cce.NonNullElements(v))); - Contract.Invariant(cce.NonNullElements(callGraph.Nodes)); - Contract.Invariant(procPriority != null); - Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtEntry)); - Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtExit) && - Contract.ForAll(varsLiveAtExit.Values, v => cce.NonNullElements(v))); - Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveSummary)); - Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheAfterCall)); - Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheBeforeCall)); - } - - - [NotDelayed] - public InterProcGenKill(Implementation impl, Program program) { - Contract.Requires(program != null); - Contract.Requires(impl != null); - this.program = program; - procICFG = new Dictionary(); - name2Proc = new Dictionary(); - workList = new WorkList(); - this.callers = new Dictionary/*!*/>(); - this.callGraph = new Graph(); - this.procPriority = new Dictionary(); - this.maxBlocksInProc = 0; - this.mainImpl = impl; - - Dictionary/*!*/ name2Impl = new Dictionary(); - varsLiveAtExit.Clear(); - varsLiveAtEntry.Clear(); - varsLiveSummary.Clear(); - - foreach (var decl in program.TopLevelDeclarations) { - Contract.Assert(decl != null); - if (decl is Implementation) { - Implementation/*!*/ imp = (Implementation/*!*/)cce.NonNull(decl); - name2Impl[imp.Name] = imp; - } else if (decl is Procedure) { - Procedure/*!*/ proc = cce.NonNull(decl as Procedure); - name2Proc[proc.Name] = proc; - } - } - - ICFG/*!*/ mainICFG = new ICFG(mainImpl); - Contract.Assert(mainICFG != null); - procICFG.Add(mainICFG.impl.Name, mainICFG); - callGraph.AddSource(mainICFG.impl.Name); - - List/*!*/ procsToConsider = new List(); - procsToConsider.Add(mainICFG); - - while (procsToConsider.Count != 0) { - ICFG/*!*/ p = procsToConsider[0]; - Contract.Assert(p != null); - procsToConsider.RemoveAt(0); - - foreach (string/*!*/ callee in p.procsCalled.Keys) { - Contract.Assert(callee != null); - if (!name2Impl.ContainsKey(callee)) - continue; - - callGraph.AddEdge(p.impl.Name, callee); - - if (maxBlocksInProc < p.nodes.Count) { - maxBlocksInProc = p.nodes.Count; - } - - if (!callers.ContainsKey(callee)) { - callers.Add(callee, new List()); - } - foreach (Block/*!*/ b in p.procsCalled[callee]) { - Contract.Assert(b != null); - callers[callee].Add(new WorkItem(p, b)); - } - - if (procICFG.ContainsKey(callee)) - continue; - ICFG/*!*/ ncfg = new ICFG(name2Impl[callee]); - Contract.Assert(ncfg != null); - procICFG.Add(callee, ncfg); - procsToConsider.Add(ncfg); - } - } - - bool acyclic; - List/*!*/ sortedNodes; - callGraph.TarjanTopSort(out acyclic, out sortedNodes); - - Contract.Assert(acyclic); - - int cnt = 0; - for (int i = sortedNodes.Count - 1; i >= 0; i--) { - string s = sortedNodes[i]; - if (s == null) - continue; - procPriority.Add(s, cnt); - cnt++; - } - - } - - public static HashSet/*!*/ GetVarsLiveAtExit(Implementation impl, Program prog) { - Contract.Requires(prog != null); - Contract.Requires(impl != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - if (varsLiveAtExit.ContainsKey(impl.Name)) { - return varsLiveAtExit[impl.Name]; - } - // Return default: all globals and out params - HashSet/*!*/ lv = new HashSet(); - foreach (Variable/*!*/ v in prog.GlobalVariables) { - Contract.Assert(v != null); - lv.Add(v); - } - foreach (Variable/*!*/ v in impl.OutParams) { - Contract.Assert(v != null); - lv.Add(v); - } - return lv; - } - - public static HashSet/*!*/ GetVarsLiveAtEntry(Implementation impl, Program prog) { - Contract.Requires(prog != null); - Contract.Requires(impl != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - if (varsLiveAtEntry.ContainsKey(impl.Name)) { - return varsLiveAtEntry[impl.Name]; - } - // Return default: all globals and in params - HashSet/*!*/ lv = new HashSet(); - foreach (Variable/*!*/ v in prog.GlobalVariables) { - Contract.Assert(v != null); - lv.Add(v); - } - foreach (Variable/*!*/ v in impl.InParams) { - Contract.Assert(v != null); - lv.Add(v); - } - return lv; - } - - public static bool HasSummary(string name) { - Contract.Requires(name != null); - return varsLiveSummary.ContainsKey(name); - } - - public static HashSet/*!*/ PropagateLiveVarsAcrossCall(CallCmd cmd, HashSet/*!*/ lvAfter) { - Contract.Requires(cmd != null); - Contract.Requires(cce.NonNullElements(lvAfter)); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Procedure/*!*/ proc = cce.NonNull(cmd.Proc); - if (varsLiveSummary.ContainsKey(proc.Name)) { - GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd); - Contract.Assert(w1 != null); - GenKillWeight/*!*/ w2 = varsLiveSummary[proc.Name]; - Contract.Assert(w2 != null); - GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd); - Contract.Assert(w3 != null); - GenKillWeight/*!*/ w = GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3)); - Contract.Assert(w != null); - return w.getLiveVars(lvAfter); - } - HashSet/*!*/ ret = new HashSet(); - ret.UnionWith(lvAfter); - LiveVariableAnalysis.Propagate(cmd, ret); - return ret; - } - - class WorkItem { - public ICFG/*!*/ cfg; - public Block/*!*/ block; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cfg != null); - Contract.Invariant(block != null); - } - - - public WorkItem(ICFG cfg, Block block) { - Contract.Requires(block != null); - Contract.Requires(cfg != null); - this.cfg = cfg; - this.block = block; - } - - public GenKillWeight getWeightAfter() { - Contract.Ensures(Contract.Result() != null); - return cfg.weightAfter[block]; - } - - public bool setWeightBefore(GenKillWeight w) { - Contract.Requires(w != null); - GenKillWeight/*!*/ prev = cfg.weightBefore[block]; - Contract.Assert(prev != null); - GenKillWeight/*!*/ curr = GenKillWeight.combine(w, prev); - Contract.Assert(curr != null); - if (GenKillWeight.isEqual(prev, curr)) - return false; - cfg.weightBefore[block] = curr; - return true; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - WorkItem/*!*/ wi = (WorkItem/*!*/)cce.NonNull(other); - return (wi.cfg == cfg && wi.block == block); - } - - [Pure] - public override int GetHashCode() { - return 0; - } - - public string getLabel() { - Contract.Ensures(Contract.Result() != null); - return cfg.impl.Name + "::" + block.Label; - } - - } - - private void AddToWorkList(WorkItem wi) { - Contract.Requires(wi != null); - int i = procPriority[wi.cfg.impl.Name]; - int j = wi.cfg.getPriority(wi.block); - int priority = (i * maxBlocksInProc) + j; - - workList.Add(wi, priority); - } - - private void AddToWorkListReverse(WorkItem wi) { - Contract.Requires(wi != null); - int i = procPriority[wi.cfg.impl.Name]; - int j = wi.cfg.getPriority(wi.block); - int priority = (procPriority.Count - i) * maxBlocksInProc + j; - workList.Add(wi, priority); - } - - class WorkList { - SortedList/*!*/ priorities; - HashSet/*!*/ labels; - - Dictionary/*!*/>/*!*/ workList; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(priorities != null); - Contract.Invariant(cce.NonNullElements(labels)); - Contract.Invariant(cce.NonNullDictionaryAndValues(workList) && - Contract.ForAll(workList.Values, v => cce.NonNullElements(v))); - } - - - public WorkList() { - labels = new HashSet(); - priorities = new SortedList(); - workList = new Dictionary/*!*/>(); - } - - public void Add(WorkItem wi, int priority) { - Contract.Requires(wi != null); - string/*!*/ lab = wi.getLabel(); - Contract.Assert(lab != null); - if (labels.Contains(lab)) { - // Already on worklist - return; - } - labels.Add(lab); - if (!workList.ContainsKey(priority)) { - workList.Add(priority, new List()); - } - workList[priority].Add(wi); - if (!priorities.ContainsKey(priority)) { - priorities.Add(priority, 0); - } - - priorities[priority] = priorities[priority] + 1; - } - - public WorkItem Get() { - Contract.Ensures(Contract.Result() != null); - // Get minimum priority - int p = cce.NonNull(priorities.Keys)[0]; - priorities[p] = priorities[p] - 1; - if (priorities[p] == 0) { - priorities.Remove(p); - } - - // Get a WI with this priority - WorkItem/*!*/ wi = workList[p][0]; - Contract.Assert(wi != null); - workList[p].RemoveAt(0); - - // update labels - labels.Remove(wi.getLabel()); - return wi; - } - - public int Count { - get { - return labels.Count; - } - } - } - - private GenKillWeight getSummary(CallCmd cmd) { - Contract.Requires(cmd != null); - Contract.Ensures(Contract.Result() != null); - Contract.Assert(cmd.Proc != null); - string/*!*/ procName = cmd.Proc.Name; - Contract.Assert(procName != null); - if (procICFG.ContainsKey(procName)) { - ICFG/*!*/ cfg = procICFG[procName]; - Contract.Assert(cfg != null); - return GenKillWeight.projectLocals(cfg.summary); - } - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - - public static void ComputeLiveVars(Implementation impl, Program/*!*/ prog) { - Contract.Requires(prog != null); - Contract.Requires(impl != null); - InterProcGenKill/*!*/ ipgk = new InterProcGenKill(impl, prog); - Contract.Assert(ipgk != null); - ipgk.Compute(); - } - - public void Compute() { - // Put all exit nodes in the worklist - foreach (ICFG/*!*/ cfg in procICFG.Values) { - Contract.Assert(cfg != null); - foreach (Block/*!*/ eb in cfg.exitNodes) { - Contract.Assert(eb != null); - WorkItem/*!*/ wi = new WorkItem(cfg, eb); - Contract.Assert(wi != null); - cfg.weightAfter[eb] = GenKillWeight.one(); - AddToWorkList(wi); - } - } - - while (workList.Count != 0) { - WorkItem/*!*/ wi = workList.Get(); - Contract.Assert(wi != null); - process(wi); - } - - // Propagate LV to all procedures - foreach (ICFG/*!*/ cfg in procICFG.Values) { - Contract.Assert(cfg != null); - foreach (Block/*!*/ b in cfg.nodes) { - Contract.Assert(b != null); - cfg.liveVarsAfter.Add(b, new HashSet()); - cfg.liveVarsBefore.Add(b, new HashSet()); - } - } - - ICFG/*!*/ mainCfg = procICFG[mainImpl.Name]; - Contract.Assert(mainCfg != null); - foreach (Block/*!*/ eb in mainCfg.exitNodes) { - Contract.Assert(eb != null); - WorkItem/*!*/ wi = new WorkItem(mainCfg, eb); - Contract.Assert(wi != null); - AddToWorkListReverse(wi); - } - - while (workList.Count != 0) { - WorkItem/*!*/ wi = workList.Get(); - Contract.Assert(wi != null); - processLV(wi); - } - - // Set live variable info - foreach (ICFG/*!*/ cfg in procICFG.Values) { - Contract.Assert(cfg != null); - HashSet/*!*/ lv = new HashSet(); - foreach (Block/*!*/ eb in cfg.exitNodes) { - Contract.Assert(eb != null); - lv.UnionWith(cfg.liveVarsAfter[eb]); - } - varsLiveAtExit.Add(cfg.impl.Name, lv); - lv = new HashSet(); - foreach (Block/*!*/ eb in cfg.srcNodes) { - Contract.Assert(eb != null); - lv.UnionWith(cfg.liveVarsBefore[eb]); - } - varsLiveAtEntry.Add(cfg.impl.Name, lv); - varsLiveSummary.Add(cfg.impl.Name, cfg.summary); - } - - /* - foreach(Block/*!*/ - /* b in mainImpl.Blocks){ -Contract.Assert(b != null); -//Set lv = cfg.weightBefore[b].getLiveVars(); -b.liveVarsBefore = procICFG[mainImpl.Name].liveVarsAfter[b]; -//foreach(GlobalVariable/*!*/ - /* v in program.GlobalVariables){Contract.Assert(v != null); -// b.liveVarsBefore.Add(v); -//} -} -*/ - } - - // Called when summaries have already been computed - private void processLV(WorkItem wi) { - Contract.Requires(wi != null); - ICFG/*!*/ cfg = wi.cfg; - Contract.Assert(cfg != null); - Block/*!*/ block = wi.block; - Contract.Assert(block != null); - HashSet/*!*/ lv = cfg.liveVarsAfter[block]; - Contract.Assert(cce.NonNullElements(lv)); - // Propagate backwards in the block - HashSet/*!*/ prop = new HashSet(); - prop.UnionWith(lv); - for (int i = block.Cmds.Count - 1; i >= 0; i--) { - Cmd/*!*/ cmd = block.Cmds[i]; - Contract.Assert(cmd != null); - if (cmd is CallCmd) { - string/*!*/ procName = cce.NonNull(cce.NonNull((CallCmd)cmd).Proc).Name; - Contract.Assert(procName != null); - if (procICFG.ContainsKey(procName)) { - ICFG/*!*/ callee = procICFG[procName]; - Contract.Assert(callee != null); - // Inter propagation - // Remove local variables; add return variables - HashSet/*!*/ elv = new HashSet(); - foreach (Variable/*!*/ v in prop) { - Contract.Assert(v != null); - if (v is GlobalVariable) - elv.Add(v); - } - foreach (Variable/*!*/ v in callee.impl.OutParams) { - Contract.Assert(v != null); - elv.Add(v); - } - - foreach (Block/*!*/ eb in callee.exitNodes) { - Contract.Assert(eb != null); - callee.liveVarsAfter[eb].UnionWith(elv); - // TODO: check if modified before inserting - AddToWorkListReverse(new WorkItem(callee, eb)); - } - - // Continue with intra propagation - GenKillWeight/*!*/ summary = getWeightCall(cce.NonNull((CallCmd/*!*/)cmd)); - prop = summary.getLiveVars(prop); - } else { - LiveVariableAnalysis.Propagate(cmd, prop); - } - } else { - LiveVariableAnalysis.Propagate(cmd, prop); - } - } - - cfg.liveVarsBefore[block].UnionWith(prop); - - foreach (Block/*!*/ b in cfg.predEdges[block]) { - Contract.Assert(b != null); - HashSet/*!*/ prev = cfg.liveVarsAfter[b]; - Contract.Assert(cce.NonNullElements(prev)); - HashSet/*!*/ curr = new HashSet(prev); - curr.UnionWith(cfg.liveVarsBefore[block]); - Contract.Assert(cce.NonNullElements(curr)); - if (curr.Count != prev.Count) { - cfg.liveVarsAfter[b] = curr; - AddToWorkListReverse(new WorkItem(cfg, b)); - } - } - } - - private void process(WorkItem wi) { - Contract.Requires(wi != null); - GenKillWeight/*!*/ w = wi.getWeightAfter(); - Contract.Assert(w != null); - - for (int i = wi.block.Cmds.Count - 1; i >= 0; i--) { - Cmd/*!*/ c = wi.block.Cmds[i]; - Contract.Assert(c != null); - if (c is CallCmd && procICFG.ContainsKey(cce.NonNull(cce.NonNull((CallCmd)c).Proc).Name)) { - w = GenKillWeight.extend(getWeightCall(cce.NonNull((CallCmd)c)), w); - } else { - GenKillWeight/*!*/ cweight = getWeight(c, wi.cfg.impl, program); - Contract.Assert(cweight != null); - w = GenKillWeight.extend(cweight, w); - } - } - - bool change = wi.setWeightBefore(w); - - if (change && wi.cfg.srcNodes.Contains(wi.block)) { - GenKillWeight/*!*/ prev = wi.cfg.summary; - Contract.Assert(prev != null); - GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, wi.cfg.weightBefore[wi.block]); - Contract.Assert(curr != null); - if (!GenKillWeight.isEqual(prev, curr)) { - wi.cfg.summary = curr; - // push callers onto the worklist - if (callers.ContainsKey(wi.cfg.impl.Name)) { - foreach (WorkItem/*!*/ caller in callers[wi.cfg.impl.Name]) { - Contract.Assert(caller != null); - AddToWorkList(caller); - } - } - } - } - - foreach (Block/*!*/ b in wi.cfg.predEdges[wi.block]) { - Contract.Assert(b != null); - GenKillWeight/*!*/ prev = wi.cfg.weightAfter[b]; - Contract.Assert(prev != null); - GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, w); - Contract.Assert(curr != null); - if (!GenKillWeight.isEqual(prev, curr)) { - wi.cfg.weightAfter[b] = curr; - AddToWorkList(new WorkItem(wi.cfg, b)); - } - } - - } - - static Dictionary/*!*/ weightCache = new Dictionary(); - - private static GenKillWeight getWeight(Cmd cmd) { - Contract.Requires(cmd != null); - Contract.Ensures(Contract.Result() != null); - return getWeight(cmd, null, null); - } - - private GenKillWeight getWeightCall(CallCmd cmd) { - Contract.Requires(cmd != null); - Contract.Ensures(Contract.Result() != null); - GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd); - GenKillWeight/*!*/ w2 = getSummary(cmd); - GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd); - Contract.Assert(w1 != null); - Contract.Assert(w2 != null); - Contract.Assert(w3 != null); - return GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3)); - } - - private static GenKillWeight getWeight(Cmd cmd, Implementation impl, Program prog) { - Contract.Requires(cmd != null); - Contract.Ensures(Contract.Result() != null); - - if (weightCache.ContainsKey(cmd)) - return weightCache[cmd]; - - HashSet/*!*/ gen = new HashSet(); - HashSet/*!*/ kill = new HashSet(); - GenKillWeight/*!*/ ret; - - if (cmd is AssignCmd) { - AssignCmd/*!*/ assignCmd = (AssignCmd)cmd; - Contract.Assert(cmd != null); - // I must first iterate over all the targets and remove the live ones. - // After the removals are done, I must add the variables referred on - // the right side of the removed targets - foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) { - Contract.Assert(lhs != null); - Variable var = lhs.DeepAssignedVariable; - if (var != null) { - if (lhs is SimpleAssignLhs) { - // we should only remove non-map target variables because there is an implicit - // read of a map variable in an assignment to it - kill.Add(var); - } - } - } - int index = 0; - foreach (Expr/*!*/ expr in assignCmd.Rhss) { - Contract.Assert(expr != null); - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(expr); - gen.UnionWith(collector.usedVars); - AssignLhs lhs = assignCmd.Lhss[index]; - if (lhs is MapAssignLhs) { - // If the target is a map, then all indices are also read - MapAssignLhs malhs = (MapAssignLhs)lhs; - foreach (Expr e in malhs.Indexes) { - VariableCollector/*!*/ c = new VariableCollector(); - c.Visit(e); - gen.UnionWith(c.usedVars); - } - } - index++; - } - ret = new GenKillWeight(gen, kill); - } else if (cmd is HavocCmd) { - HavocCmd/*!*/ havocCmd = (HavocCmd)cce.NonNull(cmd); - foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { - Contract.Assert(expr != null); - if (expr.Decl != null) { - kill.Add(expr.Decl); - } - } - ret = new GenKillWeight(gen, kill); - } else if (cmd is PredicateCmd) { - Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd)); - PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd); - if (predicateCmd.Expr is LiteralExpr && prog != null && impl != null) { - LiteralExpr le = (LiteralExpr)predicateCmd.Expr; - if (le.IsFalse) { - var globals = prog.GlobalVariables; - Contract.Assert(cce.NonNullElements(globals)); - foreach (Variable/*!*/ v in globals) { - Contract.Assert(v != null); - kill.Add(v); - } - foreach (Variable/*!*/ v in impl.LocVars) { - Contract.Assert(v != null); - kill.Add(v); - } - foreach (Variable/*!*/ v in impl.OutParams) { - Contract.Assert(v != null); - kill.Add(v); - } - } - } else { - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(predicateCmd.Expr); - gen.UnionWith(collector.usedVars); - } - ret = new GenKillWeight(gen, kill); - } else if (cmd is CommentCmd) { - ret = new GenKillWeight(gen, kill); - // comments are just for debugging and don't affect verification - } else if (cmd is SugaredCmd) { - SugaredCmd/*!*/ sugCmd = (SugaredCmd)cmd; - Contract.Assert(sugCmd != null); - ret = getWeight(sugCmd.Desugaring, impl, prog); - } else if (cmd is StateCmd) { - StateCmd/*!*/ stCmd = (StateCmd)cmd; - Contract.Assert(stCmd != null); - List/*!*/ cmds = stCmd.Cmds; - Contract.Assert(cmds != null); - int len = cmds.Count; - ret = GenKillWeight.one(); - for (int i = len - 1; i >= 0; i--) { - GenKillWeight/*!*/ w = getWeight(cmds[i], impl, prog); - Contract.Assert(w != null); - ret = GenKillWeight.extend(w, ret); - } - foreach (Variable/*!*/ v in stCmd.Locals) { - Contract.Assert(v != null); - kill.Add(v); - } - ret = GenKillWeight.extend(new GenKillWeight(gen, kill), ret); - } else { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - - weightCache[cmd] = ret; - return ret; - } - - static Dictionary/*!*/ weightCacheAfterCall = new Dictionary(); - static Dictionary/*!*/ weightCacheBeforeCall = new Dictionary(); - - private static GenKillWeight getWeightAfterCall(Cmd cmd) { - Contract.Requires(cmd != null); - Contract.Ensures(Contract.Result() != null); - - if (weightCacheAfterCall.ContainsKey(cmd)) - return weightCacheAfterCall[cmd]; - - HashSet/*!*/ gen = new HashSet(); - HashSet/*!*/ kill = new HashSet(); - - Contract.Assert(cmd is CallCmd); - CallCmd/*!*/ ccmd = cce.NonNull((CallCmd)cmd); - - foreach (IdentifierExpr/*!*/ ie in ccmd.Outs) { - Contract.Assert(ie != null); - if (ie.Decl != null) - kill.Add(ie.Decl); - } - - // Variables in ensures are considered as "read" - foreach (Ensures/*!*/ re in cce.NonNull(ccmd.Proc).Ensures) { - Contract.Assert(re != null); - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(re.Condition); - foreach (Variable/*!*/ v in collector.usedVars) { - Contract.Assert(v != null); - if (v is GlobalVariable) { - gen.Add(v); - } - } - } - - GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill); - Contract.Assert(ret != null); - weightCacheAfterCall[cmd] = ret; - return ret; - } - - private static GenKillWeight getWeightBeforeCall(Cmd cmd) { - Contract.Requires(cmd != null); - Contract.Ensures(Contract.Result() != null); - Contract.Assert((cmd is CallCmd)); - if (weightCacheBeforeCall.ContainsKey(cmd)) - return weightCacheBeforeCall[cmd]; - - HashSet/*!*/ gen = new HashSet(); - HashSet/*!*/ kill = new HashSet(); - CallCmd/*!*/ ccmd = cce.NonNull((CallCmd/*!*/)cmd); - - foreach (Expr/*!*/ expr in ccmd.Ins) { - Contract.Assert(expr != null); - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(expr); - gen.UnionWith(collector.usedVars); - } - - Contract.Assert(ccmd.Proc != null); - - // Variables in requires are considered as "read" - foreach (Requires/*!*/ re in ccmd.Proc.Requires) { - Contract.Assert(re != null); - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(re.Condition); - foreach (Variable/*!*/ v in collector.usedVars) { - Contract.Assert(v != null); - if (v is GlobalVariable) { - gen.Add(v); - } - } - } - - // Old variables in ensures are considered as "read" - foreach (Ensures/*!*/ re in ccmd.Proc.Ensures) { - Contract.Assert(re != null); - VariableCollector/*!*/ collector = new VariableCollector(); - collector.Visit(re.Condition); - foreach (Variable/*!*/ v in collector.oldVarsUsed) { - Contract.Assert(v != null); - if (v is GlobalVariable) { - gen.Add(v); - } - } - } - - GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill); - Contract.Assert(ret != null); - weightCacheAfterCall[cmd] = ret; - return ret; - } - } - - public class TokenEliminator : ReadOnlyVisitor - { - public int TokenCount = 0; - public override Expr VisitExpr(Expr node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitExpr(node); - } - public override Variable VisitVariable(Variable node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitVariable(node); - } - public override Function VisitFunction(Function node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitFunction(node); - } - public override Implementation VisitImplementation(Implementation node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitImplementation(node); - } - public override Procedure VisitProcedure(Procedure node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitProcedure(node); - } - public override Axiom VisitAxiom(Axiom node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitAxiom(node); - } - public override Cmd VisitAssignCmd(AssignCmd node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitAssignCmd(node); - } - public override Cmd VisitAssumeCmd(AssumeCmd node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitAssumeCmd(node); - } - public override Cmd VisitHavocCmd(HavocCmd node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitHavocCmd(node); - } - public override Constant VisitConstant(Constant node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitConstant(node); - } - public override TransferCmd VisitTransferCmd(TransferCmd node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitTransferCmd(node); - } - public override Block VisitBlock(Block node) - { - node.tok = Token.NoToken; - TokenCount++; - return base.VisitBlock(node); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; + + +namespace Microsoft.Boogie { + public class UnusedVarEliminator : VariableCollector { + public static void Eliminate(Program program) { + Contract.Requires(program != null); + UnusedVarEliminator elim = new UnusedVarEliminator(); + elim.Visit(program); + } + + private UnusedVarEliminator() + : base() { + + } + + public override Implementation VisitImplementation(Implementation node) { + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + //Console.WriteLine("Procedure {0}", node.Name); + Implementation/*!*/ impl = base.VisitImplementation(node); + Contract.Assert(impl != null); + //Console.WriteLine("Old number of local variables = {0}", impl.LocVars.Length); + List/*!*/ vars = new List(); + foreach (Variable/*!*/ var in impl.LocVars) { + Contract.Assert(var != null); + if (_usedVars.Contains(var)) + vars.Add(var); + } + impl.LocVars = vars; + //Console.WriteLine("New number of local variables = {0}", impl.LocVars.Length); + //Console.WriteLine("---------------------------------"); + _usedVars.Clear(); + return impl; + } + } + + public class ModSetCollector : ReadOnlyVisitor { + private Procedure enclosingProc; + private Dictionary/*!*/>/*!*/ modSets; + private HashSet yieldingProcs; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullDictionaryAndValues(modSets)); + Contract.Invariant(Contract.ForAll(modSets.Values, v => cce.NonNullElements(v))); + } + + public ModSetCollector() { + modSets = new Dictionary/*!*/>(); + yieldingProcs = new HashSet(); + } + + private bool moreProcessingRequired; + + public void DoModSetAnalysis(Program program) { + Contract.Requires(program != null); + + if (CommandLineOptions.Clo.Trace) + { +// Console.WriteLine(); +// Console.WriteLine("Running modset analysis ..."); +// int procCount = 0; +// foreach (Declaration/*!*/ decl in program.TopLevelDeclarations) +// { +// Contract.Assert(decl != null); +// if (decl is Procedure) +// procCount++; +// } +// Console.WriteLine("Number of procedures = {0}", procCount);*/ + } + + HashSet implementedProcs = new HashSet(); + foreach (var impl in program.Implementations) { + if (impl.Proc != null) + implementedProcs.Add(impl.Proc); + } + foreach (var proc in program.Procedures) { + if (!implementedProcs.Contains(proc)) + { + enclosingProc = proc; + foreach (var expr in proc.Modifies) + { + Contract.Assert(expr != null); + ProcessVariable(expr.Decl); + } + enclosingProc = null; + } + else + { + modSets.Add(proc, new HashSet()); + } + } + + moreProcessingRequired = true; + while (moreProcessingRequired) { + moreProcessingRequired = false; + this.Visit(program); + } + + foreach (Procedure x in modSets.Keys) + { + x.Modifies = new List(); + foreach (Variable v in modSets[x]) + { + x.Modifies.Add(new IdentifierExpr(v.tok, v)); + } + } + foreach (Procedure x in yieldingProcs) + { + if (!QKeyValue.FindBoolAttribute(x.Attributes, "yields")) + { + x.AddAttribute("yields"); + } + } + +#if DEBUG_PRINT + Console.WriteLine("Number of procedures with nonempty modsets = {0}", modSets.Keys.Count); + foreach (Procedure/*!*/ x in modSets.Keys) { + Contract.Assert(x != null); + Console.Write("{0} : ", x.Name); + bool first = true; + foreach (Variable/*!*/ y in modSets[x]) { + Contract.Assert(y != null); + if (first) + first = false; + else + Console.Write(", "); + Console.Write("{0}", y.Name); + } + Console.WriteLine(""); + } +#endif + } + + public override Implementation VisitImplementation(Implementation node) { + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + enclosingProc = node.Proc; + Implementation/*!*/ ret = base.VisitImplementation(node); + Contract.Assert(ret != null); + enclosingProc = null; + + return ret; + } + public override YieldCmd VisitYieldCmd(YieldCmd node) + { + if (!yieldingProcs.Contains(enclosingProc)) + { + yieldingProcs.Add(enclosingProc); + moreProcessingRequired = true; + } + return base.VisitYieldCmd(node); + } + public override Cmd VisitAssignCmd(AssignCmd assignCmd) { + //Contract.Requires(assignCmd != null); + Contract.Ensures(Contract.Result() != null); + Cmd ret = base.VisitAssignCmd(assignCmd); + foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) { + Contract.Assert(lhs != null); + ProcessVariable(lhs.DeepAssignedVariable); + } + return ret; + } + public override Cmd VisitHavocCmd(HavocCmd havocCmd) { + //Contract.Requires(havocCmd != null); + Contract.Ensures(Contract.Result() != null); + Cmd ret = base.VisitHavocCmd(havocCmd); + foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { + Contract.Assert(expr != null); + ProcessVariable(expr.Decl); + } + return ret; + } + public override Cmd VisitCallCmd(CallCmd callCmd) { + //Contract.Requires(callCmd != null); + Contract.Ensures(Contract.Result() != null); + Cmd ret = base.VisitCallCmd(callCmd); + foreach (IdentifierExpr ie in callCmd.Outs) + { + if (ie != null) ProcessVariable(ie.Decl); + } + Procedure callee = callCmd.Proc; + if (callee == null) + return ret; + if (modSets.ContainsKey(callee)) { + foreach (Variable var in modSets[callee]) { + ProcessVariable(var); + } + } + if (!yieldingProcs.Contains(enclosingProc) && (yieldingProcs.Contains(callCmd.Proc) || callCmd.IsAsync)) + { + yieldingProcs.Add(enclosingProc); + moreProcessingRequired = true; + } + if (callCmd.IsAsync) + { + if (!yieldingProcs.Contains(callCmd.Proc)) + { + yieldingProcs.Add(callCmd.Proc); + moreProcessingRequired = true; + } + } + return ret; + } + public override Cmd VisitParCallCmd(ParCallCmd node) + { + //Contract.Requires(callCmd != null); + Contract.Ensures(Contract.Result() != null); + Cmd ret = base.VisitParCallCmd(node); + if (!yieldingProcs.Contains(enclosingProc)) + { + yieldingProcs.Add(enclosingProc); + moreProcessingRequired = true; + } + foreach (CallCmd callCmd in node.CallCmds) + { + if (!yieldingProcs.Contains(callCmd.Proc)) + { + yieldingProcs.Add(callCmd.Proc); + moreProcessingRequired = true; + } + } + return ret; + } + private void ProcessVariable(Variable var) { + Procedure/*!*/ localProc = cce.NonNull(enclosingProc); + if (var == null) + return; + if (!(var is GlobalVariable)) + return; + if (!modSets.ContainsKey(localProc)) { + modSets[localProc] = new HashSet(); + } + if (modSets[localProc].Contains(var)) + return; + moreProcessingRequired = true; + modSets[localProc].Add(var); + } + public override Expr VisitCodeExpr(CodeExpr node) { + // don't go into the code expression, since it can only modify variables local to the code expression, + // and the mod-set analysis is interested in global variables + return node; + } + } + + public class MutableVariableCollector : ReadOnlyVisitor + { + public HashSet UsedVariables = new HashSet(); + + public void AddUsedVariables(HashSet usedVariables) + { + Contract.Requires(usedVariables != null); + + foreach (var v in usedVariables) + { + UsedVariables.Add(v); + } + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + Contract.Ensures(Contract.Result() != null); + + if (node.Decl != null && node.Decl.IsMutable) + { + UsedVariables.Add(node.Decl); + } + return base.VisitIdentifierExpr(node); + } + } + + public class VariableCollector : ReadOnlyVisitor { + protected HashSet/*!*/ _usedVars; + public IEnumerable/*!*/ usedVars + { + get + { + return _usedVars.AsEnumerable(); + } + } + + protected HashSet/*!*/ _oldVarsUsed; + public IEnumerable/*!*/ oldVarsUsed + { + get + { + return _oldVarsUsed.AsEnumerable(); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(_usedVars)); + Contract.Invariant(cce.NonNullElements(_oldVarsUsed)); + } + + int insideOldExpr; + + public VariableCollector() { + _usedVars = new System.Collections.Generic.HashSet(); + _oldVarsUsed = new System.Collections.Generic.HashSet(); + insideOldExpr = 0; + } + + public override Expr VisitOldExpr(OldExpr node) { + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + insideOldExpr++; + node.Expr = this.VisitExpr(node.Expr); + insideOldExpr--; + return node; + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) { + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + if (node.Decl != null) { + _usedVars.Add(node.Decl); + if (insideOldExpr > 0) { + _oldVarsUsed.Add(node.Decl); + } + } + return node; + } + } + + public class BlockCoalescer : ReadOnlyVisitor { + public static void CoalesceBlocks(Program program) { + Contract.Requires(program != null); + BlockCoalescer blockCoalescer = new BlockCoalescer(); + blockCoalescer.Visit(program); + } + + private static HashSet/*!*/ ComputeMultiPredecessorBlocks(Implementation/*!*/ impl) { + Contract.Requires(impl != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + HashSet visitedBlocks = new HashSet(); + HashSet multiPredBlocks = new HashSet(); + Stack dfsStack = new Stack(); + dfsStack.Push(impl.Blocks[0]); + while (dfsStack.Count > 0) { + Block/*!*/ b = dfsStack.Pop(); + Contract.Assert(b != null); + if (visitedBlocks.Contains(b)) { + multiPredBlocks.Add(b); + continue; + } + visitedBlocks.Add(b); + if (b.TransferCmd == null) + continue; + if (b.TransferCmd is ReturnCmd) + continue; + Contract.Assert(b.TransferCmd is GotoCmd); + GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; + if (gotoCmd.labelTargets == null) + continue; + foreach (Block/*!*/ succ in gotoCmd.labelTargets) { + Contract.Assert(succ != null); + dfsStack.Push(succ); + } + } + return multiPredBlocks; + } + + public override Implementation VisitImplementation(Implementation impl) { + //Contract.Requires(impl != null); + Contract.Ensures(Contract.Result() != null); + //Console.WriteLine("Procedure {0}", impl.Name); + //Console.WriteLine("Initial number of blocks = {0}", impl.Blocks.Count); + + HashSet multiPredBlocks = ComputeMultiPredecessorBlocks(impl); + Contract.Assert(cce.NonNullElements(multiPredBlocks)); + HashSet visitedBlocks = new HashSet(); + HashSet removedBlocks = new HashSet(); + Stack dfsStack = new Stack(); + dfsStack.Push(impl.Blocks[0]); + while (dfsStack.Count > 0) { + Block/*!*/ b = dfsStack.Pop(); + Contract.Assert(b != null); + if (visitedBlocks.Contains(b)) + continue; + visitedBlocks.Add(b); + if (b.TransferCmd == null) + continue; + if (b.TransferCmd is ReturnCmd) + continue; + Contract.Assert(b.TransferCmd is GotoCmd); + GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; + if (gotoCmd.labelTargets == null) + continue; + if (gotoCmd.labelTargets.Count == 1) { + Block/*!*/ succ = cce.NonNull(gotoCmd.labelTargets[0]); + if (!multiPredBlocks.Contains(succ)) { + foreach (Cmd/*!*/ cmd in succ.Cmds) { + Contract.Assert(cmd != null); + b.Cmds.Add(cmd); + } + b.TransferCmd = succ.TransferCmd; + if (!b.tok.IsValid && succ.tok.IsValid) { + b.tok = succ.tok; + b.Label = succ.Label; + } + removedBlocks.Add(succ); + dfsStack.Push(b); + visitedBlocks.Remove(b); + continue; + } + } + foreach (Block/*!*/ succ in gotoCmd.labelTargets) { + Contract.Assert(succ != null); + dfsStack.Push(succ); + } + } + + List newBlocks = new List(); + foreach (Block/*!*/ b in impl.Blocks) { + Contract.Assert(b != null); + if (visitedBlocks.Contains(b) && !removedBlocks.Contains(b)) { + newBlocks.Add(b); + } + } + impl.Blocks = newBlocks; + foreach (Block b in impl.Blocks) + { + if (b.TransferCmd is ReturnCmd) continue; + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + gotoCmd.labelNames = new List(); + foreach (Block succ in gotoCmd.labelTargets) + { + gotoCmd.labelNames.Add(succ.Label); + } + } + // Console.WriteLine("Final number of blocks = {0}", impl.Blocks.Count); + return impl; + } + } + + public class LiveVariableAnalysis { + public static void ClearLiveVariables(Implementation impl) { + Contract.Requires(impl != null); + foreach (Block/*!*/ block in impl.Blocks) { + Contract.Assert(block != null); + block.liveVarsBefore = null; + } + } + + public static void ComputeLiveVariables(Implementation impl) { + Contract.Requires(impl != null); + Microsoft.Boogie.Helpers.ExtraTraceInformation("Starting live variable analysis"); + Graph dag = new Graph(); + dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph + foreach (Block b in impl.Blocks) { + GotoCmd gtc = b.TransferCmd as GotoCmd; + if (gtc != null) { + Contract.Assume(gtc.labelTargets != null); + foreach (Block/*!*/ dest in gtc.labelTargets) { + Contract.Assert(dest != null); + dag.AddEdge(dest, b); + } + } + } + + IEnumerable sortedNodes; + if (CommandLineOptions.Clo.ModifyTopologicalSorting) { + sortedNodes = dag.TopologicalSort(true); + } else { + sortedNodes = dag.TopologicalSort(); + } + foreach (Block/*!*/ block in sortedNodes) { + Contract.Assert(block != null); + HashSet/*!*/ liveVarsAfter = new HashSet(); + + // The injected assumption variables should always be considered to be live. + foreach (var v in impl.InjectedAssumptionVariables.Concat(impl.DoomedInjectedAssumptionVariables)) + { + liveVarsAfter.Add(v); + } + + if (block.TransferCmd is GotoCmd) { + GotoCmd gotoCmd = (GotoCmd)block.TransferCmd; + if (gotoCmd.labelTargets != null) { + foreach (Block/*!*/ succ in gotoCmd.labelTargets) { + Contract.Assert(succ != null); + Contract.Assert(succ.liveVarsBefore != null); + liveVarsAfter.UnionWith(succ.liveVarsBefore); + } + } + } + + List cmds = block.Cmds; + int len = cmds.Count; + for (int i = len - 1; i >= 0; i--) { + if (cmds[i] is CallCmd) { + Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc); + if (InterProcGenKill.HasSummary(proc.Name)) { + liveVarsAfter = + InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter); + continue; + } + } + Propagate(cmds[i], liveVarsAfter); + } + + block.liveVarsBefore = liveVarsAfter; + + } + } + + // perform in place update of liveSet + public static void Propagate(Cmd cmd, HashSet/*!*/ liveSet) { + Contract.Requires(cmd != null); + Contract.Requires(cce.NonNullElements(liveSet)); + if (cmd is AssignCmd) { + AssignCmd/*!*/ assignCmd = (AssignCmd)cce.NonNull(cmd); + // I must first iterate over all the targets and remove the live ones. + // After the removals are done, I must add the variables referred on + // the right side of the removed targets + + AssignCmd simpleAssignCmd = assignCmd.AsSimpleAssignCmd; + HashSet indexSet = new HashSet(); + int index = 0; + foreach (AssignLhs/*!*/ lhs in simpleAssignCmd.Lhss) { + Contract.Assert(lhs != null); + SimpleAssignLhs salhs = lhs as SimpleAssignLhs; + Contract.Assert(salhs != null); + Variable var = salhs.DeepAssignedVariable; + if (var != null && liveSet.Contains(var)) { + indexSet.Add(index); + liveSet.Remove(var); + } + index++; + } + index = 0; + foreach (Expr/*!*/ expr in simpleAssignCmd.Rhss) { + Contract.Assert(expr != null); + if (indexSet.Contains(index)) { + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(expr); + liveSet.UnionWith(collector.usedVars); + } + index++; + } + } else if (cmd is HavocCmd) { + HavocCmd/*!*/ havocCmd = (HavocCmd)cmd; + foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { + Contract.Assert(expr != null); + if (expr.Decl != null && !(QKeyValue.FindBoolAttribute(expr.Decl.Attributes, "assumption") && expr.Decl.Name.StartsWith("a##cached##"))) { + liveSet.Remove(expr.Decl); + } + } + } else if (cmd is PredicateCmd) { + Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd)); + PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd); + if (predicateCmd.Expr is LiteralExpr) { + LiteralExpr le = (LiteralExpr)predicateCmd.Expr; + if (le.IsFalse) { + liveSet.Clear(); + } + } else { + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(predicateCmd.Expr); + liveSet.UnionWith(collector.usedVars); + } + } else if (cmd is CommentCmd) { + // comments are just for debugging and don't affect verification + } else if (cmd is SugaredCmd) { + SugaredCmd/*!*/ sugCmd = (SugaredCmd)cce.NonNull(cmd); + Propagate(sugCmd.Desugaring, liveSet); + } else if (cmd is StateCmd) { + StateCmd/*!*/ stCmd = (StateCmd)cce.NonNull(cmd); + List/*!*/ cmds = cce.NonNull(stCmd.Cmds); + int len = cmds.Count; + for (int i = len - 1; i >= 0; i--) { + Propagate(cmds[i], liveSet); + } + foreach (Variable/*!*/ v in stCmd.Locals) { + Contract.Assert(v != null); + liveSet.Remove(v); + } + } else { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + } + } + + /* + // An idempotent semiring interface + abstract public class Weight { + abstract public Weight! one(); + abstract public Weight! zero(); + abstract public Weight! extend(Weight! w1, Weight! w2); + abstract public Weight! combine(Weight! w1, Weight! w2); + abstract public Weight! isEqual(Weight! w); + abstract public Weight! projectLocals() + } + */ + + // Weight domain for LiveVariableAnalysis (Gen/Kill) + + public class GenKillWeight { + // lambda S. (S - kill) union gen + HashSet/*!*/ gen; + HashSet/*!*/ kill; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(gen)); + Contract.Invariant(cce.NonNullElements(kill)); + Contract.Invariant(oneWeight != null); + Contract.Invariant(zeroWeight != null); + } + + bool isZero; + + public static GenKillWeight/*!*/ oneWeight = new GenKillWeight(new HashSet(), new HashSet()); + public static GenKillWeight/*!*/ zeroWeight = new GenKillWeight(); + + // initializes to zero + public GenKillWeight() { + this.isZero = true; + this.gen = new HashSet(); + this.kill = new HashSet(); + } + + public GenKillWeight(HashSet gen, HashSet kill) { + Contract.Requires(cce.NonNullElements(gen)); + Contract.Requires(cce.NonNullElements(kill)); + Contract.Assert(gen != null); + Contract.Assert(kill != null); + this.gen = gen; + this.kill = kill; + this.isZero = false; + } + + public static GenKillWeight one() { + Contract.Ensures(Contract.Result() != null); + return oneWeight; + } + + public static GenKillWeight zero() { + Contract.Ensures(Contract.Result() != null); + return zeroWeight; + } + + public static GenKillWeight extend(GenKillWeight w1, GenKillWeight w2) { + Contract.Requires(w2 != null); + Contract.Requires(w1 != null); + Contract.Ensures(Contract.Result() != null); + if (w1.isZero || w2.isZero) + return zero(); + + HashSet t = new HashSet(w2.gen); + t.ExceptWith(w1.kill); + HashSet g = new HashSet(w1.gen); + g.UnionWith(t); + HashSet k = new HashSet(w1.kill); + k.UnionWith(w2.kill); + return new GenKillWeight(g, k); + //return new GenKillWeight(w1.gen.Union(w2.gen.Difference(w1.kill)), w1.kill.Union(w2.kill)); + } + + public static GenKillWeight combine(GenKillWeight w1, GenKillWeight w2) { + Contract.Requires(w2 != null); + Contract.Requires(w1 != null); + Contract.Ensures(Contract.Result() != null); + if (w1.isZero) + return w2; + if (w2.isZero) + return w1; + + HashSet g = new HashSet(w1.gen); + g.UnionWith(w2.gen); + HashSet k = new HashSet(w1.kill); + k.IntersectWith(w2.kill); + return new GenKillWeight(g, k); + //return new GenKillWeight(w1.gen.Union(w2.gen), w1.kill.Intersection(w2.kill)); + } + + public static GenKillWeight projectLocals(GenKillWeight w) { + Contract.Requires(w != null); + Contract.Ensures(Contract.Result() != null); + HashSet gen = new HashSet(); + foreach (Variable v in w.gen) + { + if (isGlobal(v)) + gen.Add(v); + } + HashSet kill = new HashSet(); + foreach (Variable v in w.kill) + { + if (isGlobal(v)) + kill.Add(v); + } + + return new GenKillWeight(gen, kill); + } + + public static bool isEqual(GenKillWeight w1, GenKillWeight w2) { + Contract.Requires(w2 != null); + Contract.Requires(w1 != null); + if (w1.isZero) + return w2.isZero; + if (w2.isZero) + return w1.isZero; + + return (w1.gen.Equals(w2.gen) && w1.kill.Equals(w2.kill)); + } + + private static bool isGlobal(Variable v) { + Contract.Requires(v != null); + return (v is GlobalVariable); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format("({0},{1})", gen.ToString(), kill.ToString()); + } + + public HashSet/*!*/ getLiveVars() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return gen; + } + + public HashSet/*!*/ getLiveVars(HashSet/*!*/ lv) { + Contract.Requires(cce.NonNullElements(lv)); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + HashSet temp = new HashSet(lv); + temp.ExceptWith(kill); + temp.UnionWith(gen); + return temp; + } + + } + + public class ICFG { + public Graph/*!*/ graph; + // Map from procedure to the list of blocks that call that procedure + public Dictionary/*!*/>/*!*/ procsCalled; + public HashSet/*!*/ nodes; + public Dictionary/*!*/>/*!*/ succEdges; + public Dictionary/*!*/>/*!*/ predEdges; + private Dictionary/*!*/ priority; + + public HashSet/*!*/ srcNodes; + public HashSet/*!*/ exitNodes; + + public Dictionary/*!*/ weightBefore; + public Dictionary/*!*/ weightAfter; + public Dictionary/*!*/>/*!*/ liveVarsAfter; + public Dictionary/*!*/>/*!*/ liveVarsBefore; + + public GenKillWeight/*!*/ summary; + public Implementation/*!*/ impl; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(graph.Nodes)); + Contract.Invariant(cce.NonNullDictionaryAndValues(procsCalled)); + Contract.Invariant(cce.NonNullElements(nodes)); + Contract.Invariant(cce.NonNullDictionaryAndValues(succEdges)); + Contract.Invariant(cce.NonNullDictionaryAndValues(predEdges)); + Contract.Invariant(priority != null); + Contract.Invariant(cce.NonNullElements(srcNodes)); + Contract.Invariant(cce.NonNullElements(exitNodes)); + Contract.Invariant(cce.NonNullDictionaryAndValues(weightBefore)); + Contract.Invariant(cce.NonNullDictionaryAndValues(weightAfter)); + Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsAfter)); + Contract.Invariant(cce.NonNullDictionaryAndValues(liveVarsBefore)); + Contract.Invariant(summary != null); + Contract.Invariant(impl != null); + } + + + [NotDelayed] + public ICFG(Implementation impl) { + Contract.Requires(impl != null); + this.graph = new Graph(); + this.procsCalled = new Dictionary/*!*/>(); + this.nodes = new HashSet(); + this.succEdges = new Dictionary/*!*/>(); + this.predEdges = new Dictionary/*!*/>(); + + this.priority = new Dictionary(); + + this.srcNodes = new HashSet(); + this.exitNodes = new HashSet(); + + this.weightBefore = new Dictionary(); + this.weightAfter = new Dictionary(); + this.liveVarsAfter = new Dictionary/*!*/>(); + this.liveVarsBefore = new Dictionary/*!*/>(); + + summary = GenKillWeight.zero(); + this.impl = impl; + + Initialize(impl); + + } + + private void Initialize(Implementation impl) { + Contract.Requires(impl != null); + addSource(impl.Blocks[0]); + graph.AddSource(impl.Blocks[0]); + + foreach (Block/*!*/ b in impl.Blocks) { + Contract.Assert(b != null); + if (b.TransferCmd is ReturnCmd) { + exitNodes.Add(b); + } else { + GotoCmd gc = b.TransferCmd as GotoCmd; + Contract.Assert(gc != null); + Contract.Assert(gc.labelTargets != null); + foreach (Block/*!*/ t in gc.labelTargets) { + Contract.Assert(t != null); + addEdge(b, t); + graph.AddEdge(b, t); + } + } + + weightBefore[b] = GenKillWeight.zero(); + weightAfter[b] = GenKillWeight.zero(); + + foreach (Cmd/*!*/ c in b.Cmds) { + Contract.Assert(c != null); + if (c is CallCmd) { + CallCmd/*!*/ cc = cce.NonNull((CallCmd/*!*/)c); + Contract.Assert(cc.Proc != null); + string/*!*/ procName = cc.Proc.Name; + Contract.Assert(procName != null); + if (!procsCalled.ContainsKey(procName)) { + procsCalled.Add(procName, new List()); + } + procsCalled[procName].Add(b); + } + } + } + + List/*!*/ sortedNodes; + bool acyclic; + + graph.TarjanTopSort(out acyclic, out sortedNodes); + + if (!acyclic) { + Console.WriteLine("Warning: graph is not a dag"); + } + + int num = sortedNodes.Count; + foreach (Block/*!*/ b in sortedNodes) { + Contract.Assert(b != null); + priority.Add(b, num); + num--; + } + + } + + public int getPriority(Block b) { + Contract.Requires(b != null); + if (priority.ContainsKey(b)) + return priority[b]; + return Int32.MaxValue; + } + + private void addSource(Block b) { + Contract.Requires(b != null); + registerNode(b); + this.srcNodes.Add(b); + } + + private void addExit(Block b) { + Contract.Requires(b != null); + registerNode(b); + this.exitNodes.Add(b); + } + + private void registerNode(Block b) { + Contract.Requires(b != null); + if (!succEdges.ContainsKey(b)) { + succEdges.Add(b, new HashSet()); + } + + if (!predEdges.ContainsKey(b)) { + predEdges.Add(b, new HashSet()); + } + + nodes.Add(b); + } + + private void addEdge(Block src, Block tgt) { + Contract.Requires(tgt != null); + Contract.Requires(src != null); + registerNode(src); + registerNode(tgt); + + succEdges[src].Add(tgt); + predEdges[tgt].Add(src); + } + + + } + + // Interprocedural Gen/Kill Analysis + public class InterProcGenKill { + Program/*!*/ program; + Dictionary/*!*/ procICFG; + Dictionary/*!*/ name2Proc; + Dictionary/*!*/>/*!*/ callers; + Graph/*!*/ callGraph; + Dictionary/*!*/ procPriority; + int maxBlocksInProc; + + WorkList/*!*/ workList; + + Implementation/*!*/ mainImpl; + + static Dictionary/*!*/>/*!*/ varsLiveAtExit = new Dictionary/*!*/>(); + static Dictionary/*!*/>/*!*/ varsLiveAtEntry = new Dictionary/*!*/>(); + static Dictionary/*!*/ varsLiveSummary = new Dictionary(); + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(workList != null); + Contract.Invariant(mainImpl != null); + Contract.Invariant(program != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(procICFG)); + Contract.Invariant(cce.NonNullDictionaryAndValues(name2Proc)); + Contract.Invariant(cce.NonNullDictionaryAndValues(callers) && + Contract.ForAll(callers.Values, v => cce.NonNullElements(v))); + Contract.Invariant(cce.NonNullElements(callGraph.Nodes)); + Contract.Invariant(procPriority != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtEntry)); + Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveAtExit) && + Contract.ForAll(varsLiveAtExit.Values, v => cce.NonNullElements(v))); + Contract.Invariant(cce.NonNullDictionaryAndValues(varsLiveSummary)); + Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheAfterCall)); + Contract.Invariant(cce.NonNullDictionaryAndValues(weightCacheBeforeCall)); + } + + + [NotDelayed] + public InterProcGenKill(Implementation impl, Program program) { + Contract.Requires(program != null); + Contract.Requires(impl != null); + this.program = program; + procICFG = new Dictionary(); + name2Proc = new Dictionary(); + workList = new WorkList(); + this.callers = new Dictionary/*!*/>(); + this.callGraph = new Graph(); + this.procPriority = new Dictionary(); + this.maxBlocksInProc = 0; + this.mainImpl = impl; + + Dictionary/*!*/ name2Impl = new Dictionary(); + varsLiveAtExit.Clear(); + varsLiveAtEntry.Clear(); + varsLiveSummary.Clear(); + + foreach (var decl in program.TopLevelDeclarations) { + Contract.Assert(decl != null); + if (decl is Implementation) { + Implementation/*!*/ imp = (Implementation/*!*/)cce.NonNull(decl); + name2Impl[imp.Name] = imp; + } else if (decl is Procedure) { + Procedure/*!*/ proc = cce.NonNull(decl as Procedure); + name2Proc[proc.Name] = proc; + } + } + + ICFG/*!*/ mainICFG = new ICFG(mainImpl); + Contract.Assert(mainICFG != null); + procICFG.Add(mainICFG.impl.Name, mainICFG); + callGraph.AddSource(mainICFG.impl.Name); + + List/*!*/ procsToConsider = new List(); + procsToConsider.Add(mainICFG); + + while (procsToConsider.Count != 0) { + ICFG/*!*/ p = procsToConsider[0]; + Contract.Assert(p != null); + procsToConsider.RemoveAt(0); + + foreach (string/*!*/ callee in p.procsCalled.Keys) { + Contract.Assert(callee != null); + if (!name2Impl.ContainsKey(callee)) + continue; + + callGraph.AddEdge(p.impl.Name, callee); + + if (maxBlocksInProc < p.nodes.Count) { + maxBlocksInProc = p.nodes.Count; + } + + if (!callers.ContainsKey(callee)) { + callers.Add(callee, new List()); + } + foreach (Block/*!*/ b in p.procsCalled[callee]) { + Contract.Assert(b != null); + callers[callee].Add(new WorkItem(p, b)); + } + + if (procICFG.ContainsKey(callee)) + continue; + ICFG/*!*/ ncfg = new ICFG(name2Impl[callee]); + Contract.Assert(ncfg != null); + procICFG.Add(callee, ncfg); + procsToConsider.Add(ncfg); + } + } + + bool acyclic; + List/*!*/ sortedNodes; + callGraph.TarjanTopSort(out acyclic, out sortedNodes); + + Contract.Assert(acyclic); + + int cnt = 0; + for (int i = sortedNodes.Count - 1; i >= 0; i--) { + string s = sortedNodes[i]; + if (s == null) + continue; + procPriority.Add(s, cnt); + cnt++; + } + + } + + public static HashSet/*!*/ GetVarsLiveAtExit(Implementation impl, Program prog) { + Contract.Requires(prog != null); + Contract.Requires(impl != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + if (varsLiveAtExit.ContainsKey(impl.Name)) { + return varsLiveAtExit[impl.Name]; + } + // Return default: all globals and out params + HashSet/*!*/ lv = new HashSet(); + foreach (Variable/*!*/ v in prog.GlobalVariables) { + Contract.Assert(v != null); + lv.Add(v); + } + foreach (Variable/*!*/ v in impl.OutParams) { + Contract.Assert(v != null); + lv.Add(v); + } + return lv; + } + + public static HashSet/*!*/ GetVarsLiveAtEntry(Implementation impl, Program prog) { + Contract.Requires(prog != null); + Contract.Requires(impl != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + if (varsLiveAtEntry.ContainsKey(impl.Name)) { + return varsLiveAtEntry[impl.Name]; + } + // Return default: all globals and in params + HashSet/*!*/ lv = new HashSet(); + foreach (Variable/*!*/ v in prog.GlobalVariables) { + Contract.Assert(v != null); + lv.Add(v); + } + foreach (Variable/*!*/ v in impl.InParams) { + Contract.Assert(v != null); + lv.Add(v); + } + return lv; + } + + public static bool HasSummary(string name) { + Contract.Requires(name != null); + return varsLiveSummary.ContainsKey(name); + } + + public static HashSet/*!*/ PropagateLiveVarsAcrossCall(CallCmd cmd, HashSet/*!*/ lvAfter) { + Contract.Requires(cmd != null); + Contract.Requires(cce.NonNullElements(lvAfter)); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Procedure/*!*/ proc = cce.NonNull(cmd.Proc); + if (varsLiveSummary.ContainsKey(proc.Name)) { + GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd); + Contract.Assert(w1 != null); + GenKillWeight/*!*/ w2 = varsLiveSummary[proc.Name]; + Contract.Assert(w2 != null); + GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd); + Contract.Assert(w3 != null); + GenKillWeight/*!*/ w = GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3)); + Contract.Assert(w != null); + return w.getLiveVars(lvAfter); + } + HashSet/*!*/ ret = new HashSet(); + ret.UnionWith(lvAfter); + LiveVariableAnalysis.Propagate(cmd, ret); + return ret; + } + + class WorkItem { + public ICFG/*!*/ cfg; + public Block/*!*/ block; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cfg != null); + Contract.Invariant(block != null); + } + + + public WorkItem(ICFG cfg, Block block) { + Contract.Requires(block != null); + Contract.Requires(cfg != null); + this.cfg = cfg; + this.block = block; + } + + public GenKillWeight getWeightAfter() { + Contract.Ensures(Contract.Result() != null); + return cfg.weightAfter[block]; + } + + public bool setWeightBefore(GenKillWeight w) { + Contract.Requires(w != null); + GenKillWeight/*!*/ prev = cfg.weightBefore[block]; + Contract.Assert(prev != null); + GenKillWeight/*!*/ curr = GenKillWeight.combine(w, prev); + Contract.Assert(curr != null); + if (GenKillWeight.isEqual(prev, curr)) + return false; + cfg.weightBefore[block] = curr; + return true; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + WorkItem/*!*/ wi = (WorkItem/*!*/)cce.NonNull(other); + return (wi.cfg == cfg && wi.block == block); + } + + [Pure] + public override int GetHashCode() { + return 0; + } + + public string getLabel() { + Contract.Ensures(Contract.Result() != null); + return cfg.impl.Name + "::" + block.Label; + } + + } + + private void AddToWorkList(WorkItem wi) { + Contract.Requires(wi != null); + int i = procPriority[wi.cfg.impl.Name]; + int j = wi.cfg.getPriority(wi.block); + int priority = (i * maxBlocksInProc) + j; + + workList.Add(wi, priority); + } + + private void AddToWorkListReverse(WorkItem wi) { + Contract.Requires(wi != null); + int i = procPriority[wi.cfg.impl.Name]; + int j = wi.cfg.getPriority(wi.block); + int priority = (procPriority.Count - i) * maxBlocksInProc + j; + workList.Add(wi, priority); + } + + class WorkList { + SortedList/*!*/ priorities; + HashSet/*!*/ labels; + + Dictionary/*!*/>/*!*/ workList; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(priorities != null); + Contract.Invariant(cce.NonNullElements(labels)); + Contract.Invariant(cce.NonNullDictionaryAndValues(workList) && + Contract.ForAll(workList.Values, v => cce.NonNullElements(v))); + } + + + public WorkList() { + labels = new HashSet(); + priorities = new SortedList(); + workList = new Dictionary/*!*/>(); + } + + public void Add(WorkItem wi, int priority) { + Contract.Requires(wi != null); + string/*!*/ lab = wi.getLabel(); + Contract.Assert(lab != null); + if (labels.Contains(lab)) { + // Already on worklist + return; + } + labels.Add(lab); + if (!workList.ContainsKey(priority)) { + workList.Add(priority, new List()); + } + workList[priority].Add(wi); + if (!priorities.ContainsKey(priority)) { + priorities.Add(priority, 0); + } + + priorities[priority] = priorities[priority] + 1; + } + + public WorkItem Get() { + Contract.Ensures(Contract.Result() != null); + // Get minimum priority + int p = cce.NonNull(priorities.Keys)[0]; + priorities[p] = priorities[p] - 1; + if (priorities[p] == 0) { + priorities.Remove(p); + } + + // Get a WI with this priority + WorkItem/*!*/ wi = workList[p][0]; + Contract.Assert(wi != null); + workList[p].RemoveAt(0); + + // update labels + labels.Remove(wi.getLabel()); + return wi; + } + + public int Count { + get { + return labels.Count; + } + } + } + + private GenKillWeight getSummary(CallCmd cmd) { + Contract.Requires(cmd != null); + Contract.Ensures(Contract.Result() != null); + Contract.Assert(cmd.Proc != null); + string/*!*/ procName = cmd.Proc.Name; + Contract.Assert(procName != null); + if (procICFG.ContainsKey(procName)) { + ICFG/*!*/ cfg = procICFG[procName]; + Contract.Assert(cfg != null); + return GenKillWeight.projectLocals(cfg.summary); + } + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + + public static void ComputeLiveVars(Implementation impl, Program/*!*/ prog) { + Contract.Requires(prog != null); + Contract.Requires(impl != null); + InterProcGenKill/*!*/ ipgk = new InterProcGenKill(impl, prog); + Contract.Assert(ipgk != null); + ipgk.Compute(); + } + + public void Compute() { + // Put all exit nodes in the worklist + foreach (ICFG/*!*/ cfg in procICFG.Values) { + Contract.Assert(cfg != null); + foreach (Block/*!*/ eb in cfg.exitNodes) { + Contract.Assert(eb != null); + WorkItem/*!*/ wi = new WorkItem(cfg, eb); + Contract.Assert(wi != null); + cfg.weightAfter[eb] = GenKillWeight.one(); + AddToWorkList(wi); + } + } + + while (workList.Count != 0) { + WorkItem/*!*/ wi = workList.Get(); + Contract.Assert(wi != null); + process(wi); + } + + // Propagate LV to all procedures + foreach (ICFG/*!*/ cfg in procICFG.Values) { + Contract.Assert(cfg != null); + foreach (Block/*!*/ b in cfg.nodes) { + Contract.Assert(b != null); + cfg.liveVarsAfter.Add(b, new HashSet()); + cfg.liveVarsBefore.Add(b, new HashSet()); + } + } + + ICFG/*!*/ mainCfg = procICFG[mainImpl.Name]; + Contract.Assert(mainCfg != null); + foreach (Block/*!*/ eb in mainCfg.exitNodes) { + Contract.Assert(eb != null); + WorkItem/*!*/ wi = new WorkItem(mainCfg, eb); + Contract.Assert(wi != null); + AddToWorkListReverse(wi); + } + + while (workList.Count != 0) { + WorkItem/*!*/ wi = workList.Get(); + Contract.Assert(wi != null); + processLV(wi); + } + + // Set live variable info + foreach (ICFG/*!*/ cfg in procICFG.Values) { + Contract.Assert(cfg != null); + HashSet/*!*/ lv = new HashSet(); + foreach (Block/*!*/ eb in cfg.exitNodes) { + Contract.Assert(eb != null); + lv.UnionWith(cfg.liveVarsAfter[eb]); + } + varsLiveAtExit.Add(cfg.impl.Name, lv); + lv = new HashSet(); + foreach (Block/*!*/ eb in cfg.srcNodes) { + Contract.Assert(eb != null); + lv.UnionWith(cfg.liveVarsBefore[eb]); + } + varsLiveAtEntry.Add(cfg.impl.Name, lv); + varsLiveSummary.Add(cfg.impl.Name, cfg.summary); + } + + /* + foreach(Block/*!*/ + /* b in mainImpl.Blocks){ +Contract.Assert(b != null); +//Set lv = cfg.weightBefore[b].getLiveVars(); +b.liveVarsBefore = procICFG[mainImpl.Name].liveVarsAfter[b]; +//foreach(GlobalVariable/*!*/ + /* v in program.GlobalVariables){Contract.Assert(v != null); +// b.liveVarsBefore.Add(v); +//} +} +*/ + } + + // Called when summaries have already been computed + private void processLV(WorkItem wi) { + Contract.Requires(wi != null); + ICFG/*!*/ cfg = wi.cfg; + Contract.Assert(cfg != null); + Block/*!*/ block = wi.block; + Contract.Assert(block != null); + HashSet/*!*/ lv = cfg.liveVarsAfter[block]; + Contract.Assert(cce.NonNullElements(lv)); + // Propagate backwards in the block + HashSet/*!*/ prop = new HashSet(); + prop.UnionWith(lv); + for (int i = block.Cmds.Count - 1; i >= 0; i--) { + Cmd/*!*/ cmd = block.Cmds[i]; + Contract.Assert(cmd != null); + if (cmd is CallCmd) { + string/*!*/ procName = cce.NonNull(cce.NonNull((CallCmd)cmd).Proc).Name; + Contract.Assert(procName != null); + if (procICFG.ContainsKey(procName)) { + ICFG/*!*/ callee = procICFG[procName]; + Contract.Assert(callee != null); + // Inter propagation + // Remove local variables; add return variables + HashSet/*!*/ elv = new HashSet(); + foreach (Variable/*!*/ v in prop) { + Contract.Assert(v != null); + if (v is GlobalVariable) + elv.Add(v); + } + foreach (Variable/*!*/ v in callee.impl.OutParams) { + Contract.Assert(v != null); + elv.Add(v); + } + + foreach (Block/*!*/ eb in callee.exitNodes) { + Contract.Assert(eb != null); + callee.liveVarsAfter[eb].UnionWith(elv); + // TODO: check if modified before inserting + AddToWorkListReverse(new WorkItem(callee, eb)); + } + + // Continue with intra propagation + GenKillWeight/*!*/ summary = getWeightCall(cce.NonNull((CallCmd/*!*/)cmd)); + prop = summary.getLiveVars(prop); + } else { + LiveVariableAnalysis.Propagate(cmd, prop); + } + } else { + LiveVariableAnalysis.Propagate(cmd, prop); + } + } + + cfg.liveVarsBefore[block].UnionWith(prop); + + foreach (Block/*!*/ b in cfg.predEdges[block]) { + Contract.Assert(b != null); + HashSet/*!*/ prev = cfg.liveVarsAfter[b]; + Contract.Assert(cce.NonNullElements(prev)); + HashSet/*!*/ curr = new HashSet(prev); + curr.UnionWith(cfg.liveVarsBefore[block]); + Contract.Assert(cce.NonNullElements(curr)); + if (curr.Count != prev.Count) { + cfg.liveVarsAfter[b] = curr; + AddToWorkListReverse(new WorkItem(cfg, b)); + } + } + } + + private void process(WorkItem wi) { + Contract.Requires(wi != null); + GenKillWeight/*!*/ w = wi.getWeightAfter(); + Contract.Assert(w != null); + + for (int i = wi.block.Cmds.Count - 1; i >= 0; i--) { + Cmd/*!*/ c = wi.block.Cmds[i]; + Contract.Assert(c != null); + if (c is CallCmd && procICFG.ContainsKey(cce.NonNull(cce.NonNull((CallCmd)c).Proc).Name)) { + w = GenKillWeight.extend(getWeightCall(cce.NonNull((CallCmd)c)), w); + } else { + GenKillWeight/*!*/ cweight = getWeight(c, wi.cfg.impl, program); + Contract.Assert(cweight != null); + w = GenKillWeight.extend(cweight, w); + } + } + + bool change = wi.setWeightBefore(w); + + if (change && wi.cfg.srcNodes.Contains(wi.block)) { + GenKillWeight/*!*/ prev = wi.cfg.summary; + Contract.Assert(prev != null); + GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, wi.cfg.weightBefore[wi.block]); + Contract.Assert(curr != null); + if (!GenKillWeight.isEqual(prev, curr)) { + wi.cfg.summary = curr; + // push callers onto the worklist + if (callers.ContainsKey(wi.cfg.impl.Name)) { + foreach (WorkItem/*!*/ caller in callers[wi.cfg.impl.Name]) { + Contract.Assert(caller != null); + AddToWorkList(caller); + } + } + } + } + + foreach (Block/*!*/ b in wi.cfg.predEdges[wi.block]) { + Contract.Assert(b != null); + GenKillWeight/*!*/ prev = wi.cfg.weightAfter[b]; + Contract.Assert(prev != null); + GenKillWeight/*!*/ curr = GenKillWeight.combine(prev, w); + Contract.Assert(curr != null); + if (!GenKillWeight.isEqual(prev, curr)) { + wi.cfg.weightAfter[b] = curr; + AddToWorkList(new WorkItem(wi.cfg, b)); + } + } + + } + + static Dictionary/*!*/ weightCache = new Dictionary(); + + private static GenKillWeight getWeight(Cmd cmd) { + Contract.Requires(cmd != null); + Contract.Ensures(Contract.Result() != null); + return getWeight(cmd, null, null); + } + + private GenKillWeight getWeightCall(CallCmd cmd) { + Contract.Requires(cmd != null); + Contract.Ensures(Contract.Result() != null); + GenKillWeight/*!*/ w1 = getWeightBeforeCall(cmd); + GenKillWeight/*!*/ w2 = getSummary(cmd); + GenKillWeight/*!*/ w3 = getWeightAfterCall(cmd); + Contract.Assert(w1 != null); + Contract.Assert(w2 != null); + Contract.Assert(w3 != null); + return GenKillWeight.extend(w1, GenKillWeight.extend(w2, w3)); + } + + private static GenKillWeight getWeight(Cmd cmd, Implementation impl, Program prog) { + Contract.Requires(cmd != null); + Contract.Ensures(Contract.Result() != null); + + if (weightCache.ContainsKey(cmd)) + return weightCache[cmd]; + + HashSet/*!*/ gen = new HashSet(); + HashSet/*!*/ kill = new HashSet(); + GenKillWeight/*!*/ ret; + + if (cmd is AssignCmd) { + AssignCmd/*!*/ assignCmd = (AssignCmd)cmd; + Contract.Assert(cmd != null); + // I must first iterate over all the targets and remove the live ones. + // After the removals are done, I must add the variables referred on + // the right side of the removed targets + foreach (AssignLhs/*!*/ lhs in assignCmd.Lhss) { + Contract.Assert(lhs != null); + Variable var = lhs.DeepAssignedVariable; + if (var != null) { + if (lhs is SimpleAssignLhs) { + // we should only remove non-map target variables because there is an implicit + // read of a map variable in an assignment to it + kill.Add(var); + } + } + } + int index = 0; + foreach (Expr/*!*/ expr in assignCmd.Rhss) { + Contract.Assert(expr != null); + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(expr); + gen.UnionWith(collector.usedVars); + AssignLhs lhs = assignCmd.Lhss[index]; + if (lhs is MapAssignLhs) { + // If the target is a map, then all indices are also read + MapAssignLhs malhs = (MapAssignLhs)lhs; + foreach (Expr e in malhs.Indexes) { + VariableCollector/*!*/ c = new VariableCollector(); + c.Visit(e); + gen.UnionWith(c.usedVars); + } + } + index++; + } + ret = new GenKillWeight(gen, kill); + } else if (cmd is HavocCmd) { + HavocCmd/*!*/ havocCmd = (HavocCmd)cce.NonNull(cmd); + foreach (IdentifierExpr/*!*/ expr in havocCmd.Vars) { + Contract.Assert(expr != null); + if (expr.Decl != null) { + kill.Add(expr.Decl); + } + } + ret = new GenKillWeight(gen, kill); + } else if (cmd is PredicateCmd) { + Contract.Assert((cmd is AssertCmd || cmd is AssumeCmd)); + PredicateCmd/*!*/ predicateCmd = (PredicateCmd)cce.NonNull(cmd); + if (predicateCmd.Expr is LiteralExpr && prog != null && impl != null) { + LiteralExpr le = (LiteralExpr)predicateCmd.Expr; + if (le.IsFalse) { + var globals = prog.GlobalVariables; + Contract.Assert(cce.NonNullElements(globals)); + foreach (Variable/*!*/ v in globals) { + Contract.Assert(v != null); + kill.Add(v); + } + foreach (Variable/*!*/ v in impl.LocVars) { + Contract.Assert(v != null); + kill.Add(v); + } + foreach (Variable/*!*/ v in impl.OutParams) { + Contract.Assert(v != null); + kill.Add(v); + } + } + } else { + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(predicateCmd.Expr); + gen.UnionWith(collector.usedVars); + } + ret = new GenKillWeight(gen, kill); + } else if (cmd is CommentCmd) { + ret = new GenKillWeight(gen, kill); + // comments are just for debugging and don't affect verification + } else if (cmd is SugaredCmd) { + SugaredCmd/*!*/ sugCmd = (SugaredCmd)cmd; + Contract.Assert(sugCmd != null); + ret = getWeight(sugCmd.Desugaring, impl, prog); + } else if (cmd is StateCmd) { + StateCmd/*!*/ stCmd = (StateCmd)cmd; + Contract.Assert(stCmd != null); + List/*!*/ cmds = stCmd.Cmds; + Contract.Assert(cmds != null); + int len = cmds.Count; + ret = GenKillWeight.one(); + for (int i = len - 1; i >= 0; i--) { + GenKillWeight/*!*/ w = getWeight(cmds[i], impl, prog); + Contract.Assert(w != null); + ret = GenKillWeight.extend(w, ret); + } + foreach (Variable/*!*/ v in stCmd.Locals) { + Contract.Assert(v != null); + kill.Add(v); + } + ret = GenKillWeight.extend(new GenKillWeight(gen, kill), ret); + } else { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + + weightCache[cmd] = ret; + return ret; + } + + static Dictionary/*!*/ weightCacheAfterCall = new Dictionary(); + static Dictionary/*!*/ weightCacheBeforeCall = new Dictionary(); + + private static GenKillWeight getWeightAfterCall(Cmd cmd) { + Contract.Requires(cmd != null); + Contract.Ensures(Contract.Result() != null); + + if (weightCacheAfterCall.ContainsKey(cmd)) + return weightCacheAfterCall[cmd]; + + HashSet/*!*/ gen = new HashSet(); + HashSet/*!*/ kill = new HashSet(); + + Contract.Assert(cmd is CallCmd); + CallCmd/*!*/ ccmd = cce.NonNull((CallCmd)cmd); + + foreach (IdentifierExpr/*!*/ ie in ccmd.Outs) { + Contract.Assert(ie != null); + if (ie.Decl != null) + kill.Add(ie.Decl); + } + + // Variables in ensures are considered as "read" + foreach (Ensures/*!*/ re in cce.NonNull(ccmd.Proc).Ensures) { + Contract.Assert(re != null); + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(re.Condition); + foreach (Variable/*!*/ v in collector.usedVars) { + Contract.Assert(v != null); + if (v is GlobalVariable) { + gen.Add(v); + } + } + } + + GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill); + Contract.Assert(ret != null); + weightCacheAfterCall[cmd] = ret; + return ret; + } + + private static GenKillWeight getWeightBeforeCall(Cmd cmd) { + Contract.Requires(cmd != null); + Contract.Ensures(Contract.Result() != null); + Contract.Assert((cmd is CallCmd)); + if (weightCacheBeforeCall.ContainsKey(cmd)) + return weightCacheBeforeCall[cmd]; + + HashSet/*!*/ gen = new HashSet(); + HashSet/*!*/ kill = new HashSet(); + CallCmd/*!*/ ccmd = cce.NonNull((CallCmd/*!*/)cmd); + + foreach (Expr/*!*/ expr in ccmd.Ins) { + Contract.Assert(expr != null); + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(expr); + gen.UnionWith(collector.usedVars); + } + + Contract.Assert(ccmd.Proc != null); + + // Variables in requires are considered as "read" + foreach (Requires/*!*/ re in ccmd.Proc.Requires) { + Contract.Assert(re != null); + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(re.Condition); + foreach (Variable/*!*/ v in collector.usedVars) { + Contract.Assert(v != null); + if (v is GlobalVariable) { + gen.Add(v); + } + } + } + + // Old variables in ensures are considered as "read" + foreach (Ensures/*!*/ re in ccmd.Proc.Ensures) { + Contract.Assert(re != null); + VariableCollector/*!*/ collector = new VariableCollector(); + collector.Visit(re.Condition); + foreach (Variable/*!*/ v in collector.oldVarsUsed) { + Contract.Assert(v != null); + if (v is GlobalVariable) { + gen.Add(v); + } + } + } + + GenKillWeight/*!*/ ret = new GenKillWeight(gen, kill); + Contract.Assert(ret != null); + weightCacheAfterCall[cmd] = ret; + return ret; + } + } + + public class TokenEliminator : ReadOnlyVisitor + { + public int TokenCount = 0; + public override Expr VisitExpr(Expr node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitExpr(node); + } + public override Variable VisitVariable(Variable node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitVariable(node); + } + public override Function VisitFunction(Function node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitFunction(node); + } + public override Implementation VisitImplementation(Implementation node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitImplementation(node); + } + public override Procedure VisitProcedure(Procedure node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitProcedure(node); + } + public override Axiom VisitAxiom(Axiom node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitAxiom(node); + } + public override Cmd VisitAssignCmd(AssignCmd node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitAssignCmd(node); + } + public override Cmd VisitAssumeCmd(AssumeCmd node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitAssumeCmd(node); + } + public override Cmd VisitHavocCmd(HavocCmd node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitHavocCmd(node); + } + public override Constant VisitConstant(Constant node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitConstant(node); + } + public override TransferCmd VisitTransferCmd(TransferCmd node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitTransferCmd(node); + } + public override Block VisitBlock(Block node) + { + node.tok = Token.NoToken; + TokenCount++; + return base.VisitBlock(node); + } + } } \ No newline at end of file diff --git a/Test/civl/chris4.bpl b/Test/civl/chris4.bpl new file mode 100644 index 00000000..7a19f975 --- /dev/null +++ b/Test/civl/chris4.bpl @@ -0,0 +1,16 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +procedure{:yields}{:layer 94,95} Test() +{ + yield; + L: + yield; +} + +procedure{:yields}{:layer 94,95} Test2() +{ + yield; + assert{:layer 94} 2 + 2 == 3; + L: + yield; +} diff --git a/Test/civl/chris4.bpl.expect b/Test/civl/chris4.bpl.expect new file mode 100644 index 00000000..d3d00979 --- /dev/null +++ b/Test/civl/chris4.bpl.expect @@ -0,0 +1,5 @@ +chris4.bpl(13,3): Error BP5001: This assertion might not hold. +Execution trace: + chris4.bpl(12,3): anon0 + +Boogie program verifier finished with 1 verified, 1 error -- cgit v1.2.3 From 56a3836f3606fe035362be14428a412792de371b Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 17 Jun 2015 17:29:26 -0700 Subject: modified desugaring so that in commutatitivity checks copies of original codeexpr is made. --- Source/Concurrency/MoverCheck.cs | 1319 ++++++++++---------- Source/Concurrency/OwickiGries.cs | 2412 ++++++++++++++++++------------------- Source/Concurrency/TypeCheck.cs | 151 ++- Test/civl/bar.bpl.expect | 26 +- Test/civl/foo.bpl.expect | 16 +- Test/civl/parallel1.bpl.expect | 16 +- Test/civl/t1.bpl.expect | 18 +- 7 files changed, 2001 insertions(+), 1957 deletions(-) diff --git a/Source/Concurrency/MoverCheck.cs b/Source/Concurrency/MoverCheck.cs index ed069d5d..7c6d4ac4 100644 --- a/Source/Concurrency/MoverCheck.cs +++ b/Source/Concurrency/MoverCheck.cs @@ -1,648 +1,673 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - public class MoverCheck - { - LinearTypeChecker linearTypeChecker; - MoverTypeChecker moverTypeChecker; - List decls; - HashSet> commutativityCheckerCache; - HashSet> gatePreservationCheckerCache; - HashSet> failurePreservationCheckerCache; - private MoverCheck(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) - { - this.linearTypeChecker = linearTypeChecker; - this.moverTypeChecker = moverTypeChecker; - this.decls = decls; - this.commutativityCheckerCache = new HashSet>(); - this.gatePreservationCheckerCache = new HashSet>(); - this.failurePreservationCheckerCache = new HashSet>(); - } - - public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) - { - if (moverTypeChecker.procToActionInfo.Count == 0) - return; - - List sortedByCreatedLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); - sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; }); - List sortedByAvailableUptoLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); - sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; }); - - Dictionary> pools = new Dictionary>(); - int indexIntoSortedByCreatedLayerNum = 0; - int indexIntoSortedByAvailableUptoLayerNum = 0; - HashSet currPool = new HashSet(); - while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) - { - var currLayerNum = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum].createdAtLayerNum; - pools[currLayerNum] = new HashSet(currPool); - while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) - { - var actionInfo = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum] as AtomicActionInfo; - if (actionInfo.createdAtLayerNum > currLayerNum) break; - pools[currLayerNum].Add(actionInfo); - indexIntoSortedByCreatedLayerNum++; - } - while (indexIntoSortedByAvailableUptoLayerNum < sortedByAvailableUptoLayerNum.Count) - { - var actionInfo = sortedByAvailableUptoLayerNum[indexIntoSortedByAvailableUptoLayerNum] as AtomicActionInfo; - if (actionInfo.availableUptoLayerNum > currLayerNum) break; - pools[currLayerNum].Remove(actionInfo); - indexIntoSortedByAvailableUptoLayerNum++; - } - currPool = pools[currLayerNum]; - } - - Program program = moverTypeChecker.program; - MoverCheck moverChecking = new MoverCheck(linearTypeChecker, moverTypeChecker, decls); - foreach (int layerNum in pools.Keys) - { - foreach (AtomicActionInfo first in pools[layerNum]) - { - Debug.Assert(first.moverType != MoverType.Top); - if (first.moverType == MoverType.Atomic) - continue; - foreach (AtomicActionInfo second in pools[layerNum]) - { - if (first.IsRightMover) - { - moverChecking.CreateCommutativityChecker(program, first, second); - moverChecking.CreateGatePreservationChecker(program, second, first); - } - if (first.IsLeftMover) - { - moverChecking.CreateCommutativityChecker(program, second, first); - moverChecking.CreateGatePreservationChecker(program, first, second); - moverChecking.CreateFailurePreservationChecker(program, second, first); - } - } - } - } - foreach (AtomicActionInfo atomicActionInfo in sortedByCreatedLayerNum) - { - if (atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) - { - moverChecking.CreateNonBlockingChecker(program, atomicActionInfo); - } - } - } - - public sealed class MyDuplicator : Duplicator - { - public override Expr VisitIdentifierExpr(IdentifierExpr node) - { - IdentifierExpr ret = (IdentifierExpr) base.VisitIdentifierExpr(node); - if (ret.Decl is GlobalVariable) - { - return new OldExpr(Token.NoToken, ret); - } - else - { - return ret; - } - } - } - - public class TransitionRelationComputation - { - private Program program; - private AtomicActionInfo first; // corresponds to that* - private AtomicActionInfo second; // corresponds to this* - private Stack cmdStack; - private List paths; - private HashSet frame; - private HashSet postExistVars; - - public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet frame, HashSet postExistVars) - { - this.postExistVars = postExistVars; - this.frame = frame; - TransitionRelationComputationHelper(program, null, second); - } - - public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame, HashSet postExistVars) - { - this.postExistVars = postExistVars; - this.frame = frame; - TransitionRelationComputationHelper(program, first, second); - } - - private void TransitionRelationComputationHelper(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - this.program = program; - this.first = first; - this.second = second; - this.cmdStack = new Stack(); - this.paths = new List(); - List havocVars = new List(); - this.second.thisOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); - this.second.thisAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); - if (havocVars.Count > 0) - { - HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); - cmdStack.Push(havocCmd); - } - Search(this.second.thisAction.Blocks[0], false); - } - - private void Substitute(Dictionary map, ref List pathExprs, ref Dictionary varToExpr) - { - Substitution subst = Substituter.SubstitutionFromHashtable(map); - List oldPathExprs = pathExprs; - pathExprs = new List(); - foreach (Expr pathExpr in oldPathExprs) - { - pathExprs.Add(Substituter.Apply(subst, pathExpr)); - } - Dictionary oldVarToExpr = varToExpr; - varToExpr = new Dictionary(); - foreach (Variable v in oldVarToExpr.Keys) - { - varToExpr[v] = Substituter.Apply(subst, oldVarToExpr[v]); - } - } - - struct PathInfo - { - public HashSet existsVars; - public Dictionary varToExpr; - public List pathExprs; - - public PathInfo(HashSet existsVars, Dictionary varToExpr, List pathExprs) - { - this.existsVars = existsVars; - this.varToExpr = varToExpr; - this.pathExprs = pathExprs; - } - } - - private void FlattenAnd(Expr x, List xs) - { - NAryExpr naryExpr = x as NAryExpr; - if (naryExpr != null && naryExpr.Fun.FunctionName == "&&") - { - FlattenAnd(naryExpr.Args[0], xs); - FlattenAnd(naryExpr.Args[1], xs); - } - else - { - xs.Add(x); - } - } - - private void AddPath() - { - HashSet existsVars = new HashSet(); - Dictionary varToExpr = new Dictionary(); - foreach (Variable v in frame) - { - varToExpr[v] = Expr.Ident(v); - } - if (first != null) - { - foreach (Variable v in first.thatOutParams) - { - varToExpr[v] = Expr.Ident(v); - } - } - foreach (Variable v in second.thisOutParams) - { - varToExpr[v] = Expr.Ident(v); - } - List pathExprs = new List(); - int boundVariableCount = 0; - foreach (Cmd cmd in cmdStack) - { - if (cmd is AssumeCmd) - { - AssumeCmd assumeCmd = cmd as AssumeCmd; - FlattenAnd(assumeCmd.Expr, pathExprs); - } - else if (cmd is AssignCmd) - { - AssignCmd assignCmd = (cmd as AssignCmd).AsSimpleAssignCmd; - Dictionary map = new Dictionary(); - for (int k = 0; k < assignCmd.Lhss.Count; k++) - { - map[assignCmd.Lhss[k].DeepAssignedVariable] = assignCmd.Rhss[k]; - } - Substitute(map, ref pathExprs, ref varToExpr); - } - else if (cmd is HavocCmd) - { - HavocCmd havocCmd = cmd as HavocCmd; - Dictionary map = new Dictionary(); - foreach (IdentifierExpr ie in havocCmd.Vars) - { - BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "#tmp_" + boundVariableCount++, ie.Decl.TypedIdent.Type)); - map[ie.Decl] = Expr.Ident(bv); - existsVars.Add(bv); - } - Substitute(map, ref pathExprs, ref varToExpr); - } - else - { - Debug.Assert(false); - } - } - paths.Add(new PathInfo(existsVars, varToExpr, pathExprs)); - } - - private Expr CalculatePathCondition(PathInfo path) - { - Expr returnExpr = Expr.True; - - HashSet existsVars = path.existsVars; - Dictionary existsMap = new Dictionary(); - - Dictionary varToExpr = path.varToExpr; - foreach (Variable v in varToExpr.Keys) - { - if (postExistVars.Contains(v)) continue; - IdentifierExpr ie = varToExpr[v] as IdentifierExpr; - if (ie != null && !existsMap.ContainsKey(ie.Decl) && existsVars.Contains(ie.Decl)) - { - existsMap[ie.Decl] = Expr.Ident(v); - existsVars.Remove(ie.Decl); - } - else - { - returnExpr = Expr.And(returnExpr, Expr.Eq(Expr.Ident(v), (new MyDuplicator()).VisitExpr(varToExpr[v]))); - returnExpr.Type = Type.Bool; - } - } - - List pathExprs = new List(); - path.pathExprs.ForEach(x => pathExprs.Add((new MyDuplicator()).VisitExpr(x))); - foreach (Expr x in pathExprs) - { - Variable boundVar; - Expr boundVarExpr; - if (InferSubstitution(x, out boundVar, out boundVarExpr) && existsVars.Contains(boundVar)) - { - existsMap[boundVar] = boundVarExpr; - existsVars.Remove(boundVar); - } - else - { - returnExpr = Expr.And(returnExpr, x); - returnExpr.Type = Type.Bool; - } - } - - returnExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(existsMap), returnExpr); - if (existsVars.Count > 0) - { - returnExpr = new ExistsExpr(Token.NoToken, new List(existsVars), returnExpr); - } - return returnExpr; - } - - bool InferSubstitution(Expr x, out Variable var, out Expr expr) - { - var = null; - expr = null; - NAryExpr naryExpr = x as NAryExpr; - if (naryExpr == null || naryExpr.Fun.FunctionName != "==") - { - return false; - } - IdentifierExpr arg0 = naryExpr.Args[0] as IdentifierExpr; - if (arg0 != null && arg0.Decl is BoundVariable) - { - var = arg0.Decl; - expr = naryExpr.Args[1]; - return true; - } - IdentifierExpr arg1 = naryExpr.Args[1] as IdentifierExpr; - if (arg1 != null && arg1.Decl is BoundVariable) - { - var = arg1.Decl; - expr = naryExpr.Args[0]; - return true; - } - return false; - } - - public Expr TransitionRelationCompute() - { - Expr transitionRelation = Expr.False; - foreach (PathInfo path in paths) - { - transitionRelation = Expr.Or(transitionRelation, CalculatePathCondition(path)); - } - ResolutionContext rc = new ResolutionContext(null); - rc.StateMode = ResolutionContext.State.Two; - transitionRelation.Resolve(rc); - transitionRelation.Typecheck(new TypecheckingContext(null)); - return transitionRelation; - } - - private void Search(Block b, bool inFirst) - { - int pathSizeAtEntry = cmdStack.Count; - foreach (Cmd cmd in b.Cmds) - { - cmdStack.Push(cmd); - } - if (b.TransferCmd is ReturnCmd) - { - if (first == null || inFirst) - { - AddPath(); - } - else - { - List havocVars = new List(); - first.thatOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); - first.thatAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); - if (havocVars.Count > 0) - { - HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); - cmdStack.Push(havocCmd); - } - Search(first.thatAction.Blocks[0], true); - } - } - else - { - GotoCmd gotoCmd = b.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - Search(target, inFirst); - } - } - Debug.Assert(cmdStack.Count >= pathSizeAtEntry); - while (cmdStack.Count > pathSizeAtEntry) - { - cmdStack.Pop(); - } - } - } - - private static List CloneBlocks(List blocks) - { - Dictionary blockMap = new Dictionary(); - List otherBlocks = new List(); - foreach (Block block in blocks) - { - List otherCmds = new List(); - foreach (Cmd cmd in block.Cmds) - { - otherCmds.Add(cmd); - } - Block otherBlock = new Block(); - otherBlock.Cmds = otherCmds; - otherBlock.Label = block.Label; - otherBlocks.Add(otherBlock); - blockMap[block] = otherBlock; - } - foreach (Block block in blocks) - { - if (block.TransferCmd is ReturnCmd) continue; - List otherGotoCmdLabelTargets = new List(); - List otherGotoCmdLabelNames = new List(); - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - otherGotoCmdLabelTargets.Add(blockMap[target]); - otherGotoCmdLabelNames.Add(blockMap[target].Label); - } - blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); - } - return otherBlocks; - } - - private List DisjointnessRequires(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame) - { - List requires = new List(); - Dictionary> domainNameToScope = new Dictionary>(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - domainNameToScope[domainName] = new HashSet(); - } - foreach (Variable v in frame) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - domainNameToScope[domainName].Add(v); - } - if (first != null) - { - foreach (Variable v in first.thatInParams) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - domainNameToScope[domainName].Add(v); - } - } - foreach (Variable v in second.thisInParams) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - domainNameToScope[domainName].Add(v); - } - foreach (string domainName in domainNameToScope.Keys) - { - requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); - } - return requires; - } - - private void CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) - return; - if (first.CommutesWith(second)) - return; - Tuple actionPair = new Tuple(first, second); - if (commutativityCheckerCache.Contains(actionPair)) - return; - commutativityCheckerCache.Add(actionPair); - - List inputs = new List(); - inputs.AddRange(first.thatInParams); - inputs.AddRange(second.thisInParams); - List outputs = new List(); - outputs.AddRange(first.thatOutParams); - outputs.AddRange(second.thisOutParams); - List locals = new List(); - locals.AddRange(first.thatAction.LocVars); - locals.AddRange(second.thisAction.LocVars); - List firstBlocks = CloneBlocks(first.thatAction.Blocks); - List secondBlocks = CloneBlocks(second.thisAction.Blocks); - foreach (Block b in firstBlocks) - { - if (b.TransferCmd is ReturnCmd) - { - List bs = new List(); - bs.Add(secondBlocks[0]); - List ls = new List(); - ls.Add(secondBlocks[0].Label); - b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); - } - } - List blocks = new List(); - blocks.AddRange(firstBlocks); - blocks.AddRange(secondBlocks); - HashSet frame = new HashSet(); - frame.UnionWith(first.gateUsedGlobalVars); - frame.UnionWith(first.actionUsedGlobalVars); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, first, second, frame); - foreach (AssertCmd assertCmd in first.thatGate) - requires.Add(new Requires(false, assertCmd.Expr)); - foreach (AssertCmd assertCmd in second.thisGate) - requires.Add(new Requires(false, assertCmd.Expr)); - List ensures = new List(); - Expr transitionRelation = (new TransitionRelationComputation(program, first, second, frame, new HashSet())).TransitionRelationCompute(); - Ensures ensureCheck = new Ensures(false, transitionRelation); - ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); - ensures.Add(ensureCheck); - string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, blocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - - private void CreateGatePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) - return; - Tuple actionPair = new Tuple(first, second); - if (gatePreservationCheckerCache.Contains(actionPair)) - return; - gatePreservationCheckerCache.Add(actionPair); - - List inputs = new List(); - inputs.AddRange(first.thatInParams); - inputs.AddRange(second.thisInParams); - List outputs = new List(); - outputs.AddRange(first.thatOutParams); - outputs.AddRange(second.thisOutParams); - List locals = new List(); - locals.AddRange(second.thisAction.LocVars); - List secondBlocks = CloneBlocks(second.thisAction.Blocks); - HashSet frame = new HashSet(); - frame.UnionWith(first.gateUsedGlobalVars); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, first, second, frame); - List ensures = new List(); - foreach (AssertCmd assertCmd in first.thatGate) - { - requires.Add(new Requires(false, assertCmd.Expr)); - Ensures ensureCheck = new Ensures(assertCmd.tok, false, assertCmd.Expr, null); - ensureCheck.ErrorData = string.Format("Gate not preserved by {0}", second.proc.Name); - ensures.Add(ensureCheck); - } - foreach (AssertCmd assertCmd in second.thisGate) - requires.Add(new Requires(false, assertCmd.Expr)); - string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - - private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) - { - if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) - return; - Tuple actionPair = new Tuple(first, second); - if (failurePreservationCheckerCache.Contains(actionPair)) - return; - failurePreservationCheckerCache.Add(actionPair); - - List inputs = new List(); - inputs.AddRange(first.thatInParams); - inputs.AddRange(second.thisInParams); - List outputs = new List(); - outputs.AddRange(first.thatOutParams); - outputs.AddRange(second.thisOutParams); - List locals = new List(); - locals.AddRange(second.thisAction.LocVars); - List secondBlocks = CloneBlocks(second.thisAction.Blocks); - HashSet frame = new HashSet(); - frame.UnionWith(first.gateUsedGlobalVars); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, first, second, frame); - Expr gateExpr = Expr.True; - foreach (AssertCmd assertCmd in first.thatGate) - { - gateExpr = Expr.And(gateExpr, assertCmd.Expr); - gateExpr.Type = Type.Bool; - } - gateExpr = Expr.Not(gateExpr); - gateExpr.Type = Type.Bool; - requires.Add(new Requires(false, gateExpr)); - List ensures = new List(); - Ensures ensureCheck = new Ensures(false, gateExpr); - ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); - ensures.Add(ensureCheck); - foreach (AssertCmd assertCmd in second.thisGate) - requires.Add(new Requires(false, assertCmd.Expr)); - string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - - private void CreateNonBlockingChecker(Program program, AtomicActionInfo second) - { - List inputs = new List(); - inputs.AddRange(second.thisInParams); - - HashSet frame = new HashSet(); - frame.UnionWith(second.gateUsedGlobalVars); - frame.UnionWith(second.actionUsedGlobalVars); - List requires = DisjointnessRequires(program, null, second, frame); - foreach (AssertCmd assertCmd in second.thisGate) - { - requires.Add(new Requires(false, assertCmd.Expr)); - } - HashSet postExistVars = new HashSet(); - postExistVars.UnionWith(frame); - postExistVars.UnionWith(second.thisOutParams); - Expr ensuresExpr = (new TransitionRelationComputation(program, second, frame, postExistVars)).TransitionRelationCompute(); - List ensures = new List(); - Ensures ensureCheck = new Ensures(false, ensuresExpr); - ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); - ensures.Add(ensureCheck); - - List blocks = new List(); - blocks.Add(new Block(Token.NoToken, "L", new List(), new ReturnCmd(Token.NoToken))); - string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); - List globalVars = new List(); - moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); - Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, new List(), requires, globalVars, ensures); - Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, new List(), new List(), blocks); - impl.Proc = proc; - this.decls.Add(impl); - this.decls.Add(proc); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public class MoverCheck + { + LinearTypeChecker linearTypeChecker; + MoverTypeChecker moverTypeChecker; + List decls; + HashSet> commutativityCheckerCache; + HashSet> gatePreservationCheckerCache; + HashSet> failurePreservationCheckerCache; + private MoverCheck(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) + { + this.linearTypeChecker = linearTypeChecker; + this.moverTypeChecker = moverTypeChecker; + this.decls = decls; + this.commutativityCheckerCache = new HashSet>(); + this.gatePreservationCheckerCache = new HashSet>(); + this.failurePreservationCheckerCache = new HashSet>(); + } + + public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) + { + if (moverTypeChecker.procToActionInfo.Count == 0) + return; + + List sortedByCreatedLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); + sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; }); + List sortedByAvailableUptoLayerNum = new List(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); + sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; }); + + Dictionary> pools = new Dictionary>(); + int indexIntoSortedByCreatedLayerNum = 0; + int indexIntoSortedByAvailableUptoLayerNum = 0; + HashSet currPool = new HashSet(); + while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) + { + var currLayerNum = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum].createdAtLayerNum; + pools[currLayerNum] = new HashSet(currPool); + while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) + { + var actionInfo = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum] as AtomicActionInfo; + if (actionInfo.createdAtLayerNum > currLayerNum) break; + pools[currLayerNum].Add(actionInfo); + indexIntoSortedByCreatedLayerNum++; + } + while (indexIntoSortedByAvailableUptoLayerNum < sortedByAvailableUptoLayerNum.Count) + { + var actionInfo = sortedByAvailableUptoLayerNum[indexIntoSortedByAvailableUptoLayerNum] as AtomicActionInfo; + if (actionInfo.availableUptoLayerNum > currLayerNum) break; + pools[currLayerNum].Remove(actionInfo); + indexIntoSortedByAvailableUptoLayerNum++; + } + currPool = pools[currLayerNum]; + } + + Program program = moverTypeChecker.program; + MoverCheck moverChecking = new MoverCheck(linearTypeChecker, moverTypeChecker, decls); + foreach (int layerNum in pools.Keys) + { + foreach (AtomicActionInfo first in pools[layerNum]) + { + Debug.Assert(first.moverType != MoverType.Top); + if (first.moverType == MoverType.Atomic) + continue; + foreach (AtomicActionInfo second in pools[layerNum]) + { + if (first.IsRightMover) + { + moverChecking.CreateCommutativityChecker(program, first, second); + moverChecking.CreateGatePreservationChecker(program, second, first); + } + if (first.IsLeftMover) + { + moverChecking.CreateCommutativityChecker(program, second, first); + moverChecking.CreateGatePreservationChecker(program, first, second); + moverChecking.CreateFailurePreservationChecker(program, second, first); + } + } + } + } + foreach (AtomicActionInfo atomicActionInfo in sortedByCreatedLayerNum) + { + if (atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) + { + moverChecking.CreateNonBlockingChecker(program, atomicActionInfo); + } + } + } + + public sealed class MyDuplicator : Duplicator + { + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + IdentifierExpr ret = (IdentifierExpr) base.VisitIdentifierExpr(node); + if (ret.Decl is GlobalVariable) + { + return new OldExpr(Token.NoToken, ret); + } + else + { + return ret; + } + } + } + + public class TransitionRelationComputation + { + private Program program; + private AtomicActionInfo first; // corresponds to that* + private AtomicActionInfo second; // corresponds to this* + private Stack cmdStack; + private List paths; + private HashSet frame; + private HashSet postExistVars; + + public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet frame, HashSet postExistVars) + { + this.postExistVars = postExistVars; + this.frame = frame; + TransitionRelationComputationHelper(program, null, second); + } + + public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame, HashSet postExistVars) + { + this.postExistVars = postExistVars; + this.frame = frame; + TransitionRelationComputationHelper(program, first, second); + } + + private void TransitionRelationComputationHelper(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + this.program = program; + this.first = first; + this.second = second; + this.cmdStack = new Stack(); + this.paths = new List(); + List havocVars = new List(); + this.second.thisOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); + this.second.thisAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); + if (havocVars.Count > 0) + { + HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); + cmdStack.Push(havocCmd); + } + Search(this.second.thisAction.Blocks[0], false); + } + + private void Substitute(Dictionary map, ref List pathExprs, ref Dictionary varToExpr) + { + Substitution subst = Substituter.SubstitutionFromHashtable(map); + List oldPathExprs = pathExprs; + pathExprs = new List(); + foreach (Expr pathExpr in oldPathExprs) + { + pathExprs.Add(Substituter.Apply(subst, pathExpr)); + } + Dictionary oldVarToExpr = varToExpr; + varToExpr = new Dictionary(); + foreach (Variable v in oldVarToExpr.Keys) + { + varToExpr[v] = Substituter.Apply(subst, oldVarToExpr[v]); + } + } + + struct PathInfo + { + public HashSet existsVars; + public Dictionary varToExpr; + public List pathExprs; + + public PathInfo(HashSet existsVars, Dictionary varToExpr, List pathExprs) + { + this.existsVars = existsVars; + this.varToExpr = varToExpr; + this.pathExprs = pathExprs; + } + } + + private void FlattenAnd(Expr x, List xs) + { + NAryExpr naryExpr = x as NAryExpr; + if (naryExpr != null && naryExpr.Fun.FunctionName == "&&") + { + FlattenAnd(naryExpr.Args[0], xs); + FlattenAnd(naryExpr.Args[1], xs); + } + else + { + xs.Add(x); + } + } + + private void AddPath() + { + HashSet existsVars = new HashSet(); + Dictionary varToExpr = new Dictionary(); + foreach (Variable v in frame) + { + varToExpr[v] = Expr.Ident(v); + } + if (first != null) + { + foreach (Variable v in first.thatOutParams) + { + varToExpr[v] = Expr.Ident(v); + } + } + foreach (Variable v in second.thisOutParams) + { + varToExpr[v] = Expr.Ident(v); + } + List pathExprs = new List(); + int boundVariableCount = 0; + foreach (Cmd cmd in cmdStack) + { + if (cmd is AssumeCmd) + { + AssumeCmd assumeCmd = cmd as AssumeCmd; + FlattenAnd(assumeCmd.Expr, pathExprs); + } + else if (cmd is AssignCmd) + { + AssignCmd assignCmd = (cmd as AssignCmd).AsSimpleAssignCmd; + Dictionary map = new Dictionary(); + for (int k = 0; k < assignCmd.Lhss.Count; k++) + { + map[assignCmd.Lhss[k].DeepAssignedVariable] = assignCmd.Rhss[k]; + } + Substitute(map, ref pathExprs, ref varToExpr); + } + else if (cmd is HavocCmd) + { + HavocCmd havocCmd = cmd as HavocCmd; + Dictionary map = new Dictionary(); + foreach (IdentifierExpr ie in havocCmd.Vars) + { + BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "#tmp_" + boundVariableCount++, ie.Decl.TypedIdent.Type)); + map[ie.Decl] = Expr.Ident(bv); + existsVars.Add(bv); + } + Substitute(map, ref pathExprs, ref varToExpr); + } + else + { + Debug.Assert(false); + } + } + paths.Add(new PathInfo(existsVars, varToExpr, pathExprs)); + } + + private Expr CalculatePathCondition(PathInfo path) + { + Expr returnExpr = Expr.True; + + HashSet existsVars = path.existsVars; + Dictionary existsMap = new Dictionary(); + + Dictionary varToExpr = path.varToExpr; + foreach (Variable v in varToExpr.Keys) + { + if (postExistVars.Contains(v)) continue; + IdentifierExpr ie = varToExpr[v] as IdentifierExpr; + if (ie != null && !existsMap.ContainsKey(ie.Decl) && existsVars.Contains(ie.Decl)) + { + existsMap[ie.Decl] = Expr.Ident(v); + existsVars.Remove(ie.Decl); + } + else + { + returnExpr = Expr.And(returnExpr, Expr.Eq(Expr.Ident(v), (new MyDuplicator()).VisitExpr(varToExpr[v]))); + returnExpr.Type = Type.Bool; + } + } + + List pathExprs = new List(); + path.pathExprs.ForEach(x => pathExprs.Add((new MyDuplicator()).VisitExpr(x))); + foreach (Expr x in pathExprs) + { + Variable boundVar; + Expr boundVarExpr; + if (InferSubstitution(x, out boundVar, out boundVarExpr) && existsVars.Contains(boundVar)) + { + existsMap[boundVar] = boundVarExpr; + existsVars.Remove(boundVar); + } + else + { + returnExpr = Expr.And(returnExpr, x); + returnExpr.Type = Type.Bool; + } + } + + returnExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(existsMap), returnExpr); + if (existsVars.Count > 0) + { + returnExpr = new ExistsExpr(Token.NoToken, new List(existsVars), returnExpr); + } + return returnExpr; + } + + bool InferSubstitution(Expr x, out Variable var, out Expr expr) + { + var = null; + expr = null; + NAryExpr naryExpr = x as NAryExpr; + if (naryExpr == null || naryExpr.Fun.FunctionName != "==") + { + return false; + } + IdentifierExpr arg0 = naryExpr.Args[0] as IdentifierExpr; + if (arg0 != null && arg0.Decl is BoundVariable) + { + var = arg0.Decl; + expr = naryExpr.Args[1]; + return true; + } + IdentifierExpr arg1 = naryExpr.Args[1] as IdentifierExpr; + if (arg1 != null && arg1.Decl is BoundVariable) + { + var = arg1.Decl; + expr = naryExpr.Args[0]; + return true; + } + return false; + } + + public Expr TransitionRelationCompute(bool withOriginalInOutVariables = false) + { + Expr transitionRelation = Expr.False; + foreach (PathInfo path in paths) + { + transitionRelation = Expr.Or(transitionRelation, CalculatePathCondition(path)); + } + ResolutionContext rc = new ResolutionContext(null); + rc.StateMode = ResolutionContext.State.Two; + transitionRelation.Resolve(rc); + transitionRelation.Typecheck(new TypecheckingContext(null)); + + if (withOriginalInOutVariables) + { + Dictionary invertedMap = new Dictionary(); + if (first != null) + { + foreach (var x in first.thatMap) + { + invertedMap[((IdentifierExpr)x.Value).Decl] = Expr.Ident(x.Key); + } + } + if (second != null) + { + foreach (var x in second.thisMap) + { + invertedMap[((IdentifierExpr)x.Value).Decl] = Expr.Ident(x.Key); + } + } + Substitution subst = Substituter.SubstitutionFromHashtable(invertedMap); + return Substituter.Apply(subst, transitionRelation); + } + else + { + return transitionRelation; + } + + } + + private void Search(Block b, bool inFirst) + { + int pathSizeAtEntry = cmdStack.Count; + foreach (Cmd cmd in b.Cmds) + { + cmdStack.Push(cmd); + } + if (b.TransferCmd is ReturnCmd) + { + if (first == null || inFirst) + { + AddPath(); + } + else + { + List havocVars = new List(); + first.thatOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); + first.thatAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); + if (havocVars.Count > 0) + { + HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); + cmdStack.Push(havocCmd); + } + Search(first.thatAction.Blocks[0], true); + } + } + else + { + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + Search(target, inFirst); + } + } + Debug.Assert(cmdStack.Count >= pathSizeAtEntry); + while (cmdStack.Count > pathSizeAtEntry) + { + cmdStack.Pop(); + } + } + } + + private static List CloneBlocks(List blocks) + { + Dictionary blockMap = new Dictionary(); + List otherBlocks = new List(); + foreach (Block block in blocks) + { + List otherCmds = new List(); + foreach (Cmd cmd in block.Cmds) + { + otherCmds.Add(cmd); + } + Block otherBlock = new Block(); + otherBlock.Cmds = otherCmds; + otherBlock.Label = block.Label; + otherBlocks.Add(otherBlock); + blockMap[block] = otherBlock; + } + foreach (Block block in blocks) + { + if (block.TransferCmd is ReturnCmd) continue; + List otherGotoCmdLabelTargets = new List(); + List otherGotoCmdLabelNames = new List(); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + otherGotoCmdLabelTargets.Add(blockMap[target]); + otherGotoCmdLabelNames.Add(blockMap[target].Label); + } + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); + } + return otherBlocks; + } + + private List DisjointnessRequires(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet frame) + { + List requires = new List(); + Dictionary> domainNameToScope = new Dictionary>(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + domainNameToScope[domainName] = new HashSet(); + } + foreach (Variable v in frame) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + if (first != null) + { + foreach (Variable v in first.thatInParams) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + } + foreach (Variable v in second.thisInParams) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + foreach (string domainName in domainNameToScope.Keys) + { + requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); + } + return requires; + } + + private void CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) + return; + if (first.CommutesWith(second)) + return; + Tuple actionPair = new Tuple(first, second); + if (commutativityCheckerCache.Contains(actionPair)) + return; + commutativityCheckerCache.Add(actionPair); + + List inputs = new List(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List outputs = new List(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List locals = new List(); + locals.AddRange(first.thatAction.LocVars); + locals.AddRange(second.thisAction.LocVars); + List firstBlocks = CloneBlocks(first.thatAction.Blocks); + List secondBlocks = CloneBlocks(second.thisAction.Blocks); + foreach (Block b in firstBlocks) + { + if (b.TransferCmd is ReturnCmd) + { + List bs = new List(); + bs.Add(secondBlocks[0]); + List ls = new List(); + ls.Add(secondBlocks[0].Label); + b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); + } + } + List blocks = new List(); + blocks.AddRange(firstBlocks); + blocks.AddRange(secondBlocks); + HashSet frame = new HashSet(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(first.actionUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, first, second, frame); + foreach (AssertCmd assertCmd in first.thatGate) + requires.Add(new Requires(false, assertCmd.Expr)); + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + List ensures = new List(); + Expr transitionRelation = (new TransitionRelationComputation(program, first, second, frame, new HashSet())).TransitionRelationCompute(); + Ensures ensureCheck = new Ensures(false, transitionRelation); + ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); + ensures.Add(ensureCheck); + string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List globalVars = new List(); + moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, blocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateGatePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) + return; + Tuple actionPair = new Tuple(first, second); + if (gatePreservationCheckerCache.Contains(actionPair)) + return; + gatePreservationCheckerCache.Add(actionPair); + + List inputs = new List(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List outputs = new List(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List locals = new List(); + locals.AddRange(second.thisAction.LocVars); + List secondBlocks = CloneBlocks(second.thisAction.Blocks); + HashSet frame = new HashSet(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, first, second, frame); + List ensures = new List(); + foreach (AssertCmd assertCmd in first.thatGate) + { + requires.Add(new Requires(false, assertCmd.Expr)); + Ensures ensureCheck = new Ensures(assertCmd.tok, false, assertCmd.Expr, null); + ensureCheck.ErrorData = string.Format("Gate not preserved by {0}", second.proc.Name); + ensures.Add(ensureCheck); + } + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List globalVars = new List(); + moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) + return; + Tuple actionPair = new Tuple(first, second); + if (failurePreservationCheckerCache.Contains(actionPair)) + return; + failurePreservationCheckerCache.Add(actionPair); + + List inputs = new List(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List outputs = new List(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List locals = new List(); + locals.AddRange(second.thisAction.LocVars); + List secondBlocks = CloneBlocks(second.thisAction.Blocks); + HashSet frame = new HashSet(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, first, second, frame); + Expr gateExpr = Expr.True; + foreach (AssertCmd assertCmd in first.thatGate) + { + gateExpr = Expr.And(gateExpr, assertCmd.Expr); + gateExpr.Type = Type.Bool; + } + gateExpr = Expr.Not(gateExpr); + gateExpr.Type = Type.Bool; + requires.Add(new Requires(false, gateExpr)); + List ensures = new List(); + Ensures ensureCheck = new Ensures(false, gateExpr); + ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); + ensures.Add(ensureCheck); + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List globalVars = new List(); + moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, outputs, locals, secondBlocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateNonBlockingChecker(Program program, AtomicActionInfo second) + { + List inputs = new List(); + inputs.AddRange(second.thisInParams); + + HashSet frame = new HashSet(); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List requires = DisjointnessRequires(program, null, second, frame); + foreach (AssertCmd assertCmd in second.thisGate) + { + requires.Add(new Requires(false, assertCmd.Expr)); + } + HashSet postExistVars = new HashSet(); + postExistVars.UnionWith(frame); + postExistVars.UnionWith(second.thisOutParams); + Expr ensuresExpr = (new TransitionRelationComputation(program, second, frame, postExistVars)).TransitionRelationCompute(); + List ensures = new List(); + Ensures ensureCheck = new Ensures(false, ensuresExpr); + ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); + ensures.Add(ensureCheck); + + List blocks = new List(); + blocks.Add(new Block(Token.NoToken, "L", new List(), new ReturnCmd(Token.NoToken))); + string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); + List globalVars = new List(); + moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List(), inputs, new List(), requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List(), inputs, new List(), new List(), blocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + } } \ No newline at end of file diff --git a/Source/Concurrency/OwickiGries.cs b/Source/Concurrency/OwickiGries.cs index 626f2c4a..2ad08024 100644 --- a/Source/Concurrency/OwickiGries.cs +++ b/Source/Concurrency/OwickiGries.cs @@ -1,1206 +1,1206 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Boogie; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.GraphUtil; - -namespace Microsoft.Boogie -{ - public class MyDuplicator : Duplicator - { - MoverTypeChecker moverTypeChecker; - public int layerNum; - Procedure enclosingProc; - Implementation enclosingImpl; - public Dictionary procMap; /* Original -> Duplicate */ - public Dictionary absyMap; /* Duplicate -> Original */ - public Dictionary implMap; /* Duplicate -> Original */ - public HashSet yieldingProcs; - public List impls; - - public MyDuplicator(MoverTypeChecker moverTypeChecker, int layerNum) - { - this.moverTypeChecker = moverTypeChecker; - this.layerNum = layerNum; - this.enclosingProc = null; - this.enclosingImpl = null; - this.procMap = new Dictionary(); - this.absyMap = new Dictionary(); - this.implMap = new Dictionary(); - this.yieldingProcs = new HashSet(); - this.impls = new List(); - } - - private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List newCmds) - { - int enclosingProcLayerNum = moverTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; - Procedure originalProc = originalCallCmd.Proc; - if (moverTypeChecker.procToActionInfo.ContainsKey(originalProc)) - { - AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo; - if (atomicActionInfo != null && atomicActionInfo.thisGate.Count > 0 && layerNum == enclosingProcLayerNum) - { - newCmds.Add(new HavocCmd(Token.NoToken, new List(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) }))); - Dictionary map = new Dictionary(); - for (int i = 0; i < originalProc.InParams.Count; i++) - { - map[originalProc.InParams[i]] = callCmd.Ins[i]; - } - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) - { - newCmds.Add(Substituter.Apply(subst, assertCmd)); - } - } - } - newCmds.Add(callCmd); - } - - private void ProcessParCallCmd(ParCallCmd originalParCallCmd, ParCallCmd parCallCmd, List newCmds) - { - int maxCalleeLayerNum = 0; - foreach (CallCmd iter in originalParCallCmd.CallCmds) - { - int calleeLayerNum = moverTypeChecker.procToActionInfo[iter.Proc].createdAtLayerNum; - if (calleeLayerNum > maxCalleeLayerNum) - maxCalleeLayerNum = calleeLayerNum; - } - if (layerNum > maxCalleeLayerNum) - { - for (int i = 0; i < parCallCmd.CallCmds.Count; i++) - { - ProcessCallCmd(originalParCallCmd.CallCmds[i], parCallCmd.CallCmds[i], newCmds); - absyMap[parCallCmd.CallCmds[i]] = originalParCallCmd; - } - } - else - { - newCmds.Add(parCallCmd); - } - } - - public override List VisitCmdSeq(List cmdSeq) - { - List cmds = base.VisitCmdSeq(cmdSeq); - List newCmds = new List(); - for (int i = 0; i < cmds.Count; i++) - { - Cmd originalCmd = cmdSeq[i]; - Cmd cmd = cmds[i]; - - CallCmd originalCallCmd = originalCmd as CallCmd; - if (originalCallCmd != null) - { - ProcessCallCmd(originalCallCmd, cmd as CallCmd, newCmds); - continue; - } - - ParCallCmd originalParCallCmd = originalCmd as ParCallCmd; - if (originalParCallCmd != null) - { - ProcessParCallCmd(originalParCallCmd, cmd as ParCallCmd, newCmds); - continue; - } - - newCmds.Add(cmd); - } - return newCmds; - } - - public override YieldCmd VisitYieldCmd(YieldCmd node) - { - YieldCmd yieldCmd = base.VisitYieldCmd(node); - absyMap[yieldCmd] = node; - return yieldCmd; - } - - public override Block VisitBlock(Block node) - { - Block block = base.VisitBlock(node); - absyMap[block] = node; - return block; - } - - public override Cmd VisitCallCmd(CallCmd node) - { - CallCmd callCmd = (CallCmd) base.VisitCallCmd(node); - callCmd.Proc = VisitProcedure(callCmd.Proc); - callCmd.callee = callCmd.Proc.Name; - absyMap[callCmd] = node; - return callCmd; - } - - public override Cmd VisitParCallCmd(ParCallCmd node) - { - ParCallCmd parCallCmd = (ParCallCmd) base.VisitParCallCmd(node); - absyMap[parCallCmd] = node; - return parCallCmd; - } - - public override Procedure VisitProcedure(Procedure node) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(node)) - return node; - if (!procMap.ContainsKey(node)) - { - enclosingProc = node; - Procedure proc = (Procedure)node.Clone(); - proc.Name = string.Format("{0}_{1}", node.Name, layerNum); - proc.InParams = this.VisitVariableSeq(node.InParams); - proc.Modifies = this.VisitIdentifierExprSeq(node.Modifies); - proc.OutParams = this.VisitVariableSeq(node.OutParams); - - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[node]; - if (actionInfo.createdAtLayerNum < layerNum) - { - proc.Requires = new List(); - proc.Ensures = new List(); - Implementation impl; - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo != null) - { - CodeExpr action = (CodeExpr)VisitCodeExpr(atomicActionInfo.thisAction); - List cmds = new List(); - foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) - { - cmds.Add(new AssumeCmd(Token.NoToken, (Expr)Visit(assertCmd.Expr))); - } - Block newInitBlock = new Block(Token.NoToken, "_init", cmds, - new GotoCmd(Token.NoToken, new List(new string[] { action.Blocks[0].Label }), - new List(new Block[] { action.Blocks[0] }))); - List newBlocks = new List(); - newBlocks.Add(newInitBlock); - newBlocks.AddRange(action.Blocks); - impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, action.LocVars, newBlocks); - } - else - { - Block newInitBlock = new Block(Token.NoToken, "_init", new List(), new ReturnCmd(Token.NoToken)); - List newBlocks = new List(); - newBlocks.Add(newInitBlock); - impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, new List(), newBlocks); - } - impl.Proc = proc; - impl.Proc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - impl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - impls.Add(impl); - } - else - { - yieldingProcs.Add(proc); - proc.Requires = this.VisitRequiresSeq(node.Requires); - proc.Ensures = this.VisitEnsuresSeq(node.Ensures); - } - procMap[node] = proc; - proc.Modifies = new List(); - moverTypeChecker.SharedVariables.Iter(x => proc.Modifies.Add(Expr.Ident(x))); - } - return procMap[node]; - } - - private Variable dummyLocalVar; - public override Implementation VisitImplementation(Implementation node) - { - enclosingImpl = node; - dummyLocalVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_dummy", Type.Bool)); - Implementation impl = base.VisitImplementation(node); - implMap[impl] = node; - impl.LocVars.Add(dummyLocalVar); - impl.Name = impl.Proc.Name; - return impl; - } - - public override Requires VisitRequires(Requires node) - { - Requires requires = base.VisitRequires(node); - if (node.Free) - return requires; - if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) - requires.Condition = Expr.True; - return requires; - } - - public override Ensures VisitEnsures(Ensures node) - { - Ensures ensures = base.VisitEnsures(node); - if (node.Free) - return ensures; - AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[enclosingProc] as AtomicActionInfo; - bool isAtomicSpecification = atomicActionInfo != null && atomicActionInfo.ensures == node; - if (isAtomicSpecification || !moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) - { - ensures.Condition = Expr.True; - ensures.Attributes = OwickiGries.RemoveMoverAttribute(ensures.Attributes); - } - return ensures; - } - - public override Cmd VisitAssertCmd(AssertCmd node) - { - AssertCmd assertCmd = (AssertCmd) base.VisitAssertCmd(node); - if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) - assertCmd.Expr = Expr.True; - return assertCmd; - } - } - - public class OwickiGries - { - LinearTypeChecker linearTypeChecker; - MoverTypeChecker moverTypeChecker; - Dictionary absyMap; - Dictionary implMap; - HashSet yieldingProcs; - int layerNum; - List globalMods; - Dictionary asyncAndParallelCallDesugarings; - List yieldCheckerProcs; - List yieldCheckerImpls; - Procedure yieldProc; - - Variable pc; - Variable ok; - Expr alpha; - Expr beta; - HashSet frame; - - public OwickiGries(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, MyDuplicator duplicator) - { - this.linearTypeChecker = linearTypeChecker; - this.moverTypeChecker = moverTypeChecker; - this.absyMap = duplicator.absyMap; - this.layerNum = duplicator.layerNum; - this.implMap = duplicator.implMap; - this.yieldingProcs = duplicator.yieldingProcs; - Program program = linearTypeChecker.program; - globalMods = new List(); - foreach (Variable g in moverTypeChecker.SharedVariables) - { - globalMods.Add(Expr.Ident(g)); - } - asyncAndParallelCallDesugarings = new Dictionary(); - yieldCheckerProcs = new List(); - yieldCheckerImpls = new List(); - yieldProc = null; - } - - private IEnumerable AvailableLinearVars(Absy absy) - { - return linearTypeChecker.AvailableLinearVars(absyMap[absy]); - } - - private CallCmd CallToYieldProc(IToken tok, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) - { - List exprSeq = new List(); - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName])); - } - foreach (IdentifierExpr ie in globalMods) - { - exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl])); - } - if (yieldProc == null) - { - List inputs = new List(); - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - var domain = linearTypeChecker.linearDomains[domainName]; - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); - inputs.Add(f); - } - foreach (IdentifierExpr ie in globalMods) - { - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); - inputs.Add(f); - } - yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List(), inputs, new List(), new List(), new List(), new List()); - yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - } - CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List()); - yieldCallCmd.Proc = yieldProc; - return yieldCallCmd; - } - - private void AddCallToYieldProc(IToken tok, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) - { - if (!CommandLineOptions.Clo.TrustNonInterference) - { - CallCmd yieldCallCmd = CallToYieldProc(tok, ogOldGlobalMap, domainNameToLocalVar); - newCmds.Add(yieldCallCmd); - } - - if (pc != null) - { - Expr aa = OldEqualityExprForGlobals(ogOldGlobalMap); - Expr bb = OldEqualityExpr(ogOldGlobalMap); - - // assert pc || g_old == g || beta(i, g_old, o, g); - Expr assertExpr = Expr.Or(Expr.Ident(pc), Expr.Or(aa, beta)); - assertExpr.Typecheck(new TypecheckingContext(null)); - AssertCmd skipOrBetaAssertCmd = new AssertCmd(tok, assertExpr); - skipOrBetaAssertCmd.ErrorData = "Transition invariant in initial state violated"; - newCmds.Add(skipOrBetaAssertCmd); - - // assert pc ==> o_old == o && g_old == g; - assertExpr = Expr.Imp(Expr.Ident(pc), bb); - assertExpr.Typecheck(new TypecheckingContext(null)); - AssertCmd skipAssertCmd = new AssertCmd(tok, assertExpr); - skipAssertCmd.ErrorData = "Transition invariant in final state violated"; ; - newCmds.Add(skipAssertCmd); - - // pc, ok := g_old == g ==> pc, ok || beta(i, g_old, o, g); - List pcUpdateLHS = new List( - new AssignLhs[] { - new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)), - new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok)) - }); - List pcUpdateRHS = new List( - new Expr[] { - Expr.Imp(aa, Expr.Ident(pc)), - Expr.Or(Expr.Ident(ok), beta) - }); - foreach (Expr e in pcUpdateRHS) - { - e.Typecheck(new TypecheckingContext(null)); - } - newCmds.Add(new AssignCmd(Token.NoToken, pcUpdateLHS, pcUpdateRHS)); - } - } - - private Dictionary ComputeAvailableExprs(IEnumerable availableLinearVars, Dictionary domainNameToInputVar) - { - Dictionary domainNameToExpr = new Dictionary(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - var expr = Expr.Ident(domainNameToInputVar[domainName]); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - domainNameToExpr[domainName] = expr; - } - foreach (Variable v in availableLinearVars) - { - var domainName = linearTypeChecker.FindDomainName(v); - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - var domain = linearTypeChecker.linearDomains[domainName]; - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - domainNameToExpr[domainName] = expr; - } - return domainNameToExpr; - } - - private void AddUpdatesToOldGlobalVars(List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar, Dictionary domainNameToExpr) - { - List lhss = new List(); - List rhss = new List(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); - rhss.Add(domainNameToExpr[domainName]); - } - foreach (Variable g in ogOldGlobalMap.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); - rhss.Add(Expr.Ident(g)); - } - if (lhss.Count > 0) - { - newCmds.Add(new AssignCmd(Token.NoToken, lhss, rhss)); - } - } - - private Expr OldEqualityExpr(Dictionary ogOldGlobalMap) - { - Expr bb = Expr.True; - foreach (Variable o in ogOldGlobalMap.Keys) - { - if (o is GlobalVariable && !frame.Contains(o)) continue; - bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); - bb.Type = Type.Bool; - } - return bb; - } - - private Expr OldEqualityExprForGlobals(Dictionary ogOldGlobalMap) - { - Expr bb = Expr.True; - foreach (Variable o in ogOldGlobalMap.Keys) - { - if (o is GlobalVariable && frame.Contains(o)) - { - bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); - bb.Type = Type.Bool; - } - } - return bb; - } - - private void DesugarYield(YieldCmd yieldCmd, List cmds, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar) - { - AddCallToYieldProc(yieldCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - - if (globalMods.Count > 0) - { - newCmds.Add(new HavocCmd(Token.NoToken, globalMods)); - if (pc != null) - { - // assume pc || alpha(i, g); - Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); - assumeExpr.Type = Type.Bool; - newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); - } - } - - Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(yieldCmd), domainNameToInputVar); - AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - - for (int j = 0; j < cmds.Count; j++) - { - PredicateCmd predCmd = (PredicateCmd)cmds[j]; - newCmds.Add(new AssumeCmd(Token.NoToken, predCmd.Expr)); - } - } - - public void DesugarParallelCallCmd(List newCmds, ParCallCmd parCallCmd) - { - List parallelCalleeNames = new List(); - List ins = new List(); - List outs = new List(); - string procName = "og"; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - procName = procName + "_" + callCmd.Proc.Name; - ins.AddRange(callCmd.Ins); - outs.AddRange(callCmd.Outs); - } - Procedure proc; - if (asyncAndParallelCallDesugarings.ContainsKey(procName)) - { - proc = asyncAndParallelCallDesugarings[procName]; - } - else - { - List inParams = new List(); - List outParams = new List(); - List requiresSeq = new List(); - List ensuresSeq = new List(); - int count = 0; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - Dictionary map = new Dictionary(); - foreach (Variable x in callCmd.Proc.InParams) - { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true); - inParams.Add(y); - map[x] = Expr.Ident(y); - } - foreach (Variable x in callCmd.Proc.OutParams) - { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false); - outParams.Add(y); - map[x] = Expr.Ident(y); - } - Contract.Assume(callCmd.Proc.TypeParameters.Count == 0); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (Requires req in callCmd.Proc.Requires) - { - requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes)); - } - foreach (Ensures ens in callCmd.Proc.Ensures) - { - ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes)); - } - count++; - } - proc = new Procedure(Token.NoToken, procName, new List(), inParams, outParams, requiresSeq, globalMods, ensuresSeq); - asyncAndParallelCallDesugarings[procName] = proc; - } - CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes); - dummyCallCmd.Proc = proc; - newCmds.Add(dummyCallCmd); - } - - private void CreateYieldCheckerImpl(Implementation impl, List> yields) - { - if (yields.Count == 0) return; - - Dictionary map = new Dictionary(); - foreach (Variable local in impl.LocVars) - { - var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type)); - map[local] = Expr.Ident(copy); - } - - Program program = linearTypeChecker.program; - List locals = new List(); - List inputs = new List(); - foreach (IdentifierExpr ie in map.Values) - { - locals.Add(ie.Decl); - } - for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) - { - Variable inParam = impl.InParams[i]; - Variable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type)); - locals.Add(copy); - map[impl.InParams[i]] = Expr.Ident(copy); - } - { - int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - Variable inParam = impl.InParams[i]; - Variable copy = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type), true); - inputs.Add(copy); - map[impl.InParams[i]] = Expr.Ident(copy); - i++; - } - } - for (int i = 0; i < impl.OutParams.Count; i++) - { - Variable outParam = impl.OutParams[i]; - var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, outParam.Name, outParam.TypedIdent.Type)); - locals.Add(copy); - map[impl.OutParams[i]] = Expr.Ident(copy); - } - Dictionary ogOldLocalMap = new Dictionary(); - Dictionary assumeMap = new Dictionary(map); - foreach (IdentifierExpr ie in globalMods) - { - Variable g = ie.Decl; - var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_local_old_{0}", g.Name), g.TypedIdent.Type)); - locals.Add(copy); - ogOldLocalMap[g] = Expr.Ident(copy); - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type), true); - inputs.Add(f); - assumeMap[g] = Expr.Ident(f); - } - - Substitution assumeSubst = Substituter.SubstitutionFromHashtable(assumeMap); - Substitution oldSubst = Substituter.SubstitutionFromHashtable(ogOldLocalMap); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - List yieldCheckerBlocks = new List(); - List labels = new List(); - List labelTargets = new List(); - Block yieldCheckerBlock = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); - labels.Add(yieldCheckerBlock.Label); - labelTargets.Add(yieldCheckerBlock); - yieldCheckerBlocks.Add(yieldCheckerBlock); - int yieldCount = 0; - foreach (List cs in yields) - { - List newCmds = new List(); - foreach (Cmd cmd in cs) - { - PredicateCmd predCmd = (PredicateCmd)cmd; - newCmds.Add(new AssumeCmd(Token.NoToken, Substituter.ApplyReplacingOldExprs(assumeSubst, oldSubst, predCmd.Expr))); - } - foreach (Cmd cmd in cs) - { - PredicateCmd predCmd = (PredicateCmd)cmd; - var newExpr = Substituter.ApplyReplacingOldExprs(subst, oldSubst, predCmd.Expr); - if (predCmd is AssertCmd) - { - AssertCmd assertCmd = new AssertCmd(predCmd.tok, newExpr, predCmd.Attributes); - assertCmd.ErrorData = "Non-interference check failed"; - newCmds.Add(assertCmd); - } - else - { - newCmds.Add(new AssumeCmd(Token.NoToken, newExpr)); - } - } - newCmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); - yieldCheckerBlock = new Block(Token.NoToken, "L" + yieldCount++, newCmds, new ReturnCmd(Token.NoToken)); - labels.Add(yieldCheckerBlock.Label); - labelTargets.Add(yieldCheckerBlock); - yieldCheckerBlocks.Add(yieldCheckerBlock); - } - yieldCheckerBlocks.Insert(0, new Block(Token.NoToken, "enter", new List(), new GotoCmd(Token.NoToken, labels, labelTargets))); - - // Create the yield checker procedure - var yieldCheckerName = string.Format("{0}_YieldChecker_{1}", "Impl", impl.Name); - var yieldCheckerProc = new Procedure(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), new List(), new List(), new List()); - yieldCheckerProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - yieldCheckerProcs.Add(yieldCheckerProc); - - // Create the yield checker implementation - var yieldCheckerImpl = new Implementation(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), locals, yieldCheckerBlocks); - yieldCheckerImpl.Proc = yieldCheckerProc; - yieldCheckerImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - yieldCheckerImpls.Add(yieldCheckerImpl); - } - - private bool IsYieldingHeader(Graph graph, Block header) - { - foreach (Block backEdgeNode in graph.BackEdgeNodes(header)) - { - foreach (Block x in graph.NaturalLoops(header, backEdgeNode)) - { - foreach (Cmd cmd in x.Cmds) - { - if (cmd is YieldCmd) - return true; - if (cmd is ParCallCmd) - return true; - CallCmd callCmd = cmd as CallCmd; - if (callCmd == null) continue; - if (yieldingProcs.Contains(callCmd.Proc)) - return true; - } - } - } - return false; - } - - private Graph ComputeYieldingLoopHeaders(Implementation impl, out HashSet yieldingHeaders) - { - Graph graph; - impl.PruneUnreachableBlocks(); - impl.ComputePredecessorsForBlocks(); - graph = Program.GraphFromImpl(impl); - graph.ComputeLoops(); - if (!graph.Reducible) - { - throw new Exception("Irreducible flow graphs are unsupported."); - } - yieldingHeaders = new HashSet(); - IEnumerable sortedHeaders = graph.SortHeadersByDominance(); - foreach (Block header in sortedHeaders) - { - if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) - { - yieldingHeaders.Add(header); - } - else if (IsYieldingHeader(graph, header)) - { - yieldingHeaders.Add(header); - } - else - { - continue; - } - } - return graph; - } - - private void SetupRefinementCheck(Implementation impl, - out List newLocalVars, - out Dictionary domainNameToInputVar, out Dictionary domainNameToLocalVar, out Dictionary ogOldGlobalMap) - { - pc = null; - ok = null; - alpha = null; - beta = null; - frame = null; - - newLocalVars = new List(); - Program program = linearTypeChecker.program; - ogOldGlobalMap = new Dictionary(); - foreach (IdentifierExpr ie in globalMods) - { - Variable g = ie.Decl; - LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type)); - ogOldGlobalMap[g] = l; - newLocalVars.Add(l); - } - - Procedure originalProc = implMap[impl].Proc; - ActionInfo actionInfo = moverTypeChecker.procToActionInfo[originalProc]; - if (actionInfo.createdAtLayerNum == this.layerNum) - { - pc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_pc", Type.Bool)); - newLocalVars.Add(pc); - ok = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_ok", Type.Bool)); - newLocalVars.Add(ok); - Dictionary alwaysMap = new Dictionary(); - for (int i = 0; i < originalProc.InParams.Count; i++) - { - alwaysMap[originalProc.InParams[i]] = Expr.Ident(impl.InParams[i]); - } - for (int i = 0; i < originalProc.OutParams.Count; i++) - { - alwaysMap[originalProc.OutParams[i]] = Expr.Ident(impl.OutParams[i]); - } - Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap); - Dictionary foroldMap = new Dictionary(); - foreach (IdentifierExpr ie in globalMods) - { - foroldMap[ie.Decl] = Expr.Ident(ogOldGlobalMap[ie.Decl]); - } - Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap); - frame = new HashSet(moverTypeChecker.SharedVariables); - HashSet introducedVars = new HashSet(); - foreach (Variable v in moverTypeChecker.SharedVariables) - { - if (moverTypeChecker.globalVarToSharedVarInfo[v].hideLayerNum <= actionInfo.createdAtLayerNum || - moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum > actionInfo.createdAtLayerNum) - { - frame.Remove(v); - } - if (moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum == actionInfo.createdAtLayerNum) - { - introducedVars.Add(v); - } - } - AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; - if (atomicActionInfo == null) - { - beta = Expr.True; - foreach (var v in frame) - { - beta = Expr.And(beta, Expr.Eq(Expr.Ident(v), foroldMap[v])); - } - alpha = Expr.True; - } - else - { - Expr betaExpr = (new MoverCheck.TransitionRelationComputation(moverTypeChecker.program, atomicActionInfo, frame, introducedVars)).TransitionRelationCompute(); - beta = Substituter.ApplyReplacingOldExprs(always, forold, betaExpr); - Expr alphaExpr = Expr.True; - foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) - { - alphaExpr = Expr.And(alphaExpr, assertCmd.Expr); - alphaExpr.Type = Type.Bool; - } - alpha = Substituter.Apply(always, alphaExpr); - } - foreach (Variable f in impl.OutParams) - { - LocalVariable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_old_{0}", f.Name), f.TypedIdent.Type)); - newLocalVars.Add(copy); - ogOldGlobalMap[f] = copy; - } - } - - domainNameToInputVar = new Dictionary(); - domainNameToLocalVar = new Dictionary(); - { - int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - Variable inParam = impl.InParams[i]; - domainNameToInputVar[domainName] = inParam; - Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type)); - domainNameToLocalVar[domainName] = l; - newLocalVars.Add(l); - i++; - } - } - } - - private void TransformImpl(Implementation impl) - { - HashSet yieldingHeaders; - Graph graph = ComputeYieldingLoopHeaders(impl, out yieldingHeaders); - - List newLocalVars; - Dictionary domainNameToInputVar, domainNameToLocalVar; - Dictionary ogOldGlobalMap; - SetupRefinementCheck(impl, out newLocalVars, out domainNameToInputVar, out domainNameToLocalVar, out ogOldGlobalMap); - - List> yields = CollectAndDesugarYields(impl, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); - - List oldPcs, oldOks; - ProcessLoopHeaders(impl, graph, yieldingHeaders, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap, out oldPcs, out oldOks); - - AddInitialBlock(impl, oldPcs, oldOks, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); - - CreateYieldCheckerImpl(impl, yields); - - impl.LocVars.AddRange(newLocalVars); - impl.LocVars.AddRange(oldPcs); - impl.LocVars.AddRange(oldOks); - - UnifyCallsToYieldProc(impl, ogOldGlobalMap, domainNameToLocalVar); - } - - private void UnifyCallsToYieldProc(Implementation impl, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) - { - CallCmd yieldCallCmd = CallToYieldProc(Token.NoToken, ogOldGlobalMap, domainNameToLocalVar); - Block yieldCheckBlock = new Block(Token.NoToken, "CallToYieldProc", new List(new Cmd[] { yieldCallCmd, new AssumeCmd(Token.NoToken, Expr.False) }), new ReturnCmd(Token.NoToken)); - List newBlocks = new List(); - foreach (Block b in impl.Blocks) - { - TransferCmd transferCmd = b.TransferCmd; - List newCmds = new List(); - for (int i = b.Cmds.Count-1; i >= 0; i--) - { - CallCmd callCmd = b.Cmds[i] as CallCmd; - if (callCmd == null || callCmd.Proc != yieldProc) - { - newCmds.Insert(0, b.Cmds[i]); - } - else - { - Block newBlock = new Block(Token.NoToken, b.Label + i, newCmds, transferCmd); - newCmds = new List(); - transferCmd = new GotoCmd(Token.NoToken, new List(new string[] { newBlock.Label, yieldCheckBlock.Label }), - new List(new Block[] { newBlock, yieldCheckBlock })); - newBlocks.Add(newBlock); - } - } - b.Cmds = newCmds; - b.TransferCmd = transferCmd; - } - impl.Blocks.AddRange(newBlocks); - impl.Blocks.Add(yieldCheckBlock); - } - - private List> CollectAndDesugarYields(Implementation impl, - Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) - { - // Collect the yield predicates and desugar yields - List> yields = new List>(); - List cmds = new List(); - foreach (Block b in impl.Blocks) - { - YieldCmd yieldCmd = null; - List newCmds = new List(); - for (int i = 0; i < b.Cmds.Count; i++) - { - Cmd cmd = b.Cmds[i]; - if (cmd is YieldCmd) - { - yieldCmd = (YieldCmd)cmd; - continue; - } - if (yieldCmd != null) - { - PredicateCmd pcmd = cmd as PredicateCmd; - if (pcmd == null) - { - DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); - if (cmds.Count > 0) - { - yields.Add(cmds); - cmds = new List(); - } - yieldCmd = null; - } - else - { - cmds.Add(pcmd); - } - } - - if (cmd is CallCmd) - { - CallCmd callCmd = cmd as CallCmd; - if (yieldingProcs.Contains(callCmd.Proc)) - { - AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - } - if (callCmd.IsAsync) - { - if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) - { - asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List(), new List()); - } - var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; - CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes); - dummyCallCmd.Proc = dummyAsyncTargetProc; - newCmds.Add(dummyCallCmd); - } - else - { - newCmds.Add(callCmd); - } - if (yieldingProcs.Contains(callCmd.Proc)) - { - HashSet availableLinearVars = new HashSet(AvailableLinearVars(callCmd)); - linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); - - if (!callCmd.IsAsync && globalMods.Count > 0 && pc != null) - { - // assume pc || alpha(i, g); - Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); - assumeExpr.Type = Type.Bool; - newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); - } - - Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); - AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - } - } - else if (cmd is ParCallCmd) - { - ParCallCmd parCallCmd = cmd as ParCallCmd; - AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - DesugarParallelCallCmd(newCmds, parCallCmd); - HashSet availableLinearVars = new HashSet(AvailableLinearVars(parCallCmd)); - linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); - - if (globalMods.Count > 0 && pc != null) - { - // assume pc || alpha(i, g); - Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); - assumeExpr.Type = Type.Bool; - newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); - } - - Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); - AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - } - else - { - newCmds.Add(cmd); - } - } - if (yieldCmd != null) - { - DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); - if (cmds.Count > 0) - { - yields.Add(cmds); - cmds = new List(); - } - } - if (b.TransferCmd is ReturnCmd) - { - AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); - if (pc != null) - { - AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok)); - assertCmd.ErrorData = "Failed to execute atomic action before procedure return"; - newCmds.Add(assertCmd); - } - } - b.Cmds = newCmds; - } - return yields; - } - - private void ProcessLoopHeaders(Implementation impl, Graph graph, HashSet yieldingHeaders, - Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap, - out List oldPcs, out List oldOks) - { - oldPcs = new List(); - oldOks = new List(); - foreach (Block header in yieldingHeaders) - { - LocalVariable oldPc = null; - LocalVariable oldOk = null; - if (pc != null) - { - oldPc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", pc.Name, header.Label), Type.Bool)); - oldPcs.Add(oldPc); - oldOk = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", ok.Name, header.Label), Type.Bool)); - oldOks.Add(oldOk); - } - Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar); - foreach (Block pred in header.Predecessors) - { - AddCallToYieldProc(header.tok, pred.Cmds, ogOldGlobalMap, domainNameToLocalVar); - if (pc != null && !graph.BackEdgeNodes(header).Contains(pred)) - { - pred.Cmds.Add(new AssignCmd(Token.NoToken, new List( - new AssignLhs[] { new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)), new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)) }), - new List(new Expr[] { Expr.Ident(pc), Expr.Ident(ok) }))); - } - AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); - } - List newCmds = new List(); - if (pc != null) - { - AssertCmd assertCmd; - assertCmd = new AssertCmd(header.tok, Expr.Eq(Expr.Ident(oldPc), Expr.Ident(pc))); - assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; - newCmds.Add(assertCmd); - assertCmd = new AssertCmd(header.tok, Expr.Imp(Expr.Ident(oldOk), Expr.Ident(ok))); - assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; - newCmds.Add(assertCmd); - } - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName]))); - } - foreach (Variable v in ogOldGlobalMap.Keys) - { - newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(v), Expr.Ident(ogOldGlobalMap[v])))); - } - newCmds.AddRange(header.Cmds); - header.Cmds = newCmds; - } - } - - private void AddInitialBlock(Implementation impl, List oldPcs, List oldOks, - Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) - { - // Add initial block - List lhss = new List(); - List rhss = new List(); - if (pc != null) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc))); - rhss.Add(Expr.False); - foreach (Variable oldPc in oldPcs) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc))); - rhss.Add(Expr.False); - } - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok))); - rhss.Add(Expr.False); - foreach (Variable oldOk in oldOks) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk))); - rhss.Add(Expr.False); - } - } - Dictionary domainNameToExpr = new Dictionary(); - foreach (var domainName in linearTypeChecker.linearDomains.Keys) - { - domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); - } - for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) - { - Variable v = impl.InParams[i]; - var domainName = linearTypeChecker.FindDomainName(v); - if (domainName == null) continue; - if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; - var domain = linearTypeChecker.linearDomains[domainName]; - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); - } - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); - rhss.Add(domainNameToExpr[domainName]); - } - foreach (Variable g in ogOldGlobalMap.Keys) - { - lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); - rhss.Add(Expr.Ident(g)); - } - if (lhss.Count > 0) - { - Block initBlock = new Block(Token.NoToken, "og_init", new List { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List { impl.Blocks[0].Label }, new List { impl.Blocks[0] })); - impl.Blocks.Insert(0, initBlock); - } - } - - private void AddYieldProcAndImpl(List decls) - { - if (yieldProc == null) return; - - Program program = linearTypeChecker.program; - List inputs = new List(); - foreach (string domainName in linearTypeChecker.linearDomains.Keys) - { - var domain = linearTypeChecker.linearDomains[domainName]; - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); - inputs.Add(f); - } - foreach (IdentifierExpr ie in globalMods) - { - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); - inputs.Add(f); - } - List blocks = new List(); - TransferCmd transferCmd = new ReturnCmd(Token.NoToken); - if (yieldCheckerProcs.Count > 0) - { - List blockTargets = new List(); - List labelTargets = new List(); - int labelCount = 0; - foreach (Procedure proc in yieldCheckerProcs) - { - List exprSeq = new List(); - foreach (Variable v in inputs) - { - exprSeq.Add(Expr.Ident(v)); - } - CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List()); - callCmd.Proc = proc; - string label = string.Format("L_{0}", labelCount++); - Block block = new Block(Token.NoToken, label, new List { callCmd }, new ReturnCmd(Token.NoToken)); - labelTargets.Add(label); - blockTargets.Add(block); - blocks.Add(block); - } - transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets); - } - blocks.Insert(0, new Block(Token.NoToken, "enter", new List(), transferCmd)); - - var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List(), inputs, new List(), new List(), blocks); - yieldImpl.Proc = yieldProc; - yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); - decls.Add(yieldProc); - decls.Add(yieldImpl); - } - - public static QKeyValue RemoveYieldsAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveYieldsAttribute(iter.Next); - return (iter.Key == "yields") ? iter.Next : iter; - } - - public static QKeyValue RemoveMoverAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveMoverAttribute(iter.Next); - if (iter.Key == "atomic" || iter.Key == "right" || iter.Key == "left" || iter.Key == "both") - return iter.Next; - else - return iter; - } - - private List Collect() - { - List decls = new List(); - foreach (Procedure proc in yieldCheckerProcs) - { - decls.Add(proc); - } - foreach (Implementation impl in yieldCheckerImpls) - { - decls.Add(impl); - } - foreach (Procedure proc in asyncAndParallelCallDesugarings.Values) - { - decls.Add(proc); - } - AddYieldProcAndImpl(decls); - return decls; - } - - public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) - { - Program program = linearTypeChecker.program; - foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum })) - { - if (CommandLineOptions.Clo.TrustLayersDownto <= layerNum || layerNum <= CommandLineOptions.Clo.TrustLayersUpto) continue; - - MyDuplicator duplicator = new MyDuplicator(moverTypeChecker, layerNum); - foreach (var proc in program.Procedures) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(proc)) continue; - Procedure duplicateProc = duplicator.VisitProcedure(proc); - decls.Add(duplicateProc); - } - decls.AddRange(duplicator.impls); - OwickiGries ogTransform = new OwickiGries(linearTypeChecker, moverTypeChecker, duplicator); - foreach (var impl in program.Implementations) - { - if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc) || moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum < layerNum) - continue; - Implementation duplicateImpl = duplicator.VisitImplementation(impl); - ogTransform.TransformImpl(duplicateImpl); - decls.Add(duplicateImpl); - } - decls.AddRange(ogTransform.Collect()); - } - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Boogie; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + public class MyDuplicator : Duplicator + { + MoverTypeChecker moverTypeChecker; + public int layerNum; + Procedure enclosingProc; + Implementation enclosingImpl; + public Dictionary procMap; /* Original -> Duplicate */ + public Dictionary absyMap; /* Duplicate -> Original */ + public Dictionary implMap; /* Duplicate -> Original */ + public HashSet yieldingProcs; + public List impls; + + public MyDuplicator(MoverTypeChecker moverTypeChecker, int layerNum) + { + this.moverTypeChecker = moverTypeChecker; + this.layerNum = layerNum; + this.enclosingProc = null; + this.enclosingImpl = null; + this.procMap = new Dictionary(); + this.absyMap = new Dictionary(); + this.implMap = new Dictionary(); + this.yieldingProcs = new HashSet(); + this.impls = new List(); + } + + private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List newCmds) + { + int enclosingProcLayerNum = moverTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + Procedure originalProc = originalCallCmd.Proc; + if (moverTypeChecker.procToActionInfo.ContainsKey(originalProc)) + { + AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo; + if (atomicActionInfo != null && atomicActionInfo.gate.Count > 0 && layerNum == enclosingProcLayerNum) + { + newCmds.Add(new HavocCmd(Token.NoToken, new List(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) }))); + Dictionary map = new Dictionary(); + for (int i = 0; i < originalProc.InParams.Count; i++) + { + map[originalProc.InParams[i]] = callCmd.Ins[i]; + } + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + newCmds.Add(Substituter.Apply(subst, assertCmd)); + } + } + } + newCmds.Add(callCmd); + } + + private void ProcessParCallCmd(ParCallCmd originalParCallCmd, ParCallCmd parCallCmd, List newCmds) + { + int maxCalleeLayerNum = 0; + foreach (CallCmd iter in originalParCallCmd.CallCmds) + { + int calleeLayerNum = moverTypeChecker.procToActionInfo[iter.Proc].createdAtLayerNum; + if (calleeLayerNum > maxCalleeLayerNum) + maxCalleeLayerNum = calleeLayerNum; + } + if (layerNum > maxCalleeLayerNum) + { + for (int i = 0; i < parCallCmd.CallCmds.Count; i++) + { + ProcessCallCmd(originalParCallCmd.CallCmds[i], parCallCmd.CallCmds[i], newCmds); + absyMap[parCallCmd.CallCmds[i]] = originalParCallCmd; + } + } + else + { + newCmds.Add(parCallCmd); + } + } + + public override List VisitCmdSeq(List cmdSeq) + { + List cmds = base.VisitCmdSeq(cmdSeq); + List newCmds = new List(); + for (int i = 0; i < cmds.Count; i++) + { + Cmd originalCmd = cmdSeq[i]; + Cmd cmd = cmds[i]; + + CallCmd originalCallCmd = originalCmd as CallCmd; + if (originalCallCmd != null) + { + ProcessCallCmd(originalCallCmd, cmd as CallCmd, newCmds); + continue; + } + + ParCallCmd originalParCallCmd = originalCmd as ParCallCmd; + if (originalParCallCmd != null) + { + ProcessParCallCmd(originalParCallCmd, cmd as ParCallCmd, newCmds); + continue; + } + + newCmds.Add(cmd); + } + return newCmds; + } + + public override YieldCmd VisitYieldCmd(YieldCmd node) + { + YieldCmd yieldCmd = base.VisitYieldCmd(node); + absyMap[yieldCmd] = node; + return yieldCmd; + } + + public override Block VisitBlock(Block node) + { + Block block = base.VisitBlock(node); + absyMap[block] = node; + return block; + } + + public override Cmd VisitCallCmd(CallCmd node) + { + CallCmd callCmd = (CallCmd) base.VisitCallCmd(node); + callCmd.Proc = VisitProcedure(callCmd.Proc); + callCmd.callee = callCmd.Proc.Name; + absyMap[callCmd] = node; + return callCmd; + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + ParCallCmd parCallCmd = (ParCallCmd) base.VisitParCallCmd(node); + absyMap[parCallCmd] = node; + return parCallCmd; + } + + public override Procedure VisitProcedure(Procedure node) + { + if (!moverTypeChecker.procToActionInfo.ContainsKey(node)) + return node; + if (!procMap.ContainsKey(node)) + { + enclosingProc = node; + Procedure proc = (Procedure)node.Clone(); + proc.Name = string.Format("{0}_{1}", node.Name, layerNum); + proc.InParams = this.VisitVariableSeq(node.InParams); + proc.Modifies = this.VisitIdentifierExprSeq(node.Modifies); + proc.OutParams = this.VisitVariableSeq(node.OutParams); + + ActionInfo actionInfo = moverTypeChecker.procToActionInfo[node]; + if (actionInfo.createdAtLayerNum < layerNum) + { + proc.Requires = new List(); + proc.Ensures = new List(); + Implementation impl; + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo != null) + { + CodeExpr action = (CodeExpr)VisitCodeExpr(atomicActionInfo.action); + List cmds = new List(); + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + cmds.Add(new AssumeCmd(Token.NoToken, (Expr)Visit(assertCmd.Expr))); + } + Block newInitBlock = new Block(Token.NoToken, "_init", cmds, + new GotoCmd(Token.NoToken, new List(new string[] { action.Blocks[0].Label }), + new List(new Block[] { action.Blocks[0] }))); + List newBlocks = new List(); + newBlocks.Add(newInitBlock); + newBlocks.AddRange(action.Blocks); + impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, action.LocVars, newBlocks); + } + else + { + Block newInitBlock = new Block(Token.NoToken, "_init", new List(), new ReturnCmd(Token.NoToken)); + List newBlocks = new List(); + newBlocks.Add(newInitBlock); + impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, new List(), newBlocks); + } + impl.Proc = proc; + impl.Proc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + impl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + impls.Add(impl); + } + else + { + yieldingProcs.Add(proc); + proc.Requires = this.VisitRequiresSeq(node.Requires); + proc.Ensures = this.VisitEnsuresSeq(node.Ensures); + } + procMap[node] = proc; + proc.Modifies = new List(); + moverTypeChecker.SharedVariables.Iter(x => proc.Modifies.Add(Expr.Ident(x))); + } + return procMap[node]; + } + + private Variable dummyLocalVar; + public override Implementation VisitImplementation(Implementation node) + { + enclosingImpl = node; + dummyLocalVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_dummy", Type.Bool)); + Implementation impl = base.VisitImplementation(node); + implMap[impl] = node; + impl.LocVars.Add(dummyLocalVar); + impl.Name = impl.Proc.Name; + return impl; + } + + public override Requires VisitRequires(Requires node) + { + Requires requires = base.VisitRequires(node); + if (node.Free) + return requires; + if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) + requires.Condition = Expr.True; + return requires; + } + + public override Ensures VisitEnsures(Ensures node) + { + Ensures ensures = base.VisitEnsures(node); + if (node.Free) + return ensures; + AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[enclosingProc] as AtomicActionInfo; + bool isAtomicSpecification = atomicActionInfo != null && atomicActionInfo.ensures == node; + if (isAtomicSpecification || !moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) + { + ensures.Condition = Expr.True; + ensures.Attributes = OwickiGries.RemoveMoverAttribute(ensures.Attributes); + } + return ensures; + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + AssertCmd assertCmd = (AssertCmd) base.VisitAssertCmd(node); + if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum)) + assertCmd.Expr = Expr.True; + return assertCmd; + } + } + + public class OwickiGries + { + LinearTypeChecker linearTypeChecker; + MoverTypeChecker moverTypeChecker; + Dictionary absyMap; + Dictionary implMap; + HashSet yieldingProcs; + int layerNum; + List globalMods; + Dictionary asyncAndParallelCallDesugarings; + List yieldCheckerProcs; + List yieldCheckerImpls; + Procedure yieldProc; + + Variable pc; + Variable ok; + Expr alpha; + Expr beta; + HashSet frame; + + public OwickiGries(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, MyDuplicator duplicator) + { + this.linearTypeChecker = linearTypeChecker; + this.moverTypeChecker = moverTypeChecker; + this.absyMap = duplicator.absyMap; + this.layerNum = duplicator.layerNum; + this.implMap = duplicator.implMap; + this.yieldingProcs = duplicator.yieldingProcs; + Program program = linearTypeChecker.program; + globalMods = new List(); + foreach (Variable g in moverTypeChecker.SharedVariables) + { + globalMods.Add(Expr.Ident(g)); + } + asyncAndParallelCallDesugarings = new Dictionary(); + yieldCheckerProcs = new List(); + yieldCheckerImpls = new List(); + yieldProc = null; + } + + private IEnumerable AvailableLinearVars(Absy absy) + { + return linearTypeChecker.AvailableLinearVars(absyMap[absy]); + } + + private CallCmd CallToYieldProc(IToken tok, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) + { + List exprSeq = new List(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName])); + } + foreach (IdentifierExpr ie in globalMods) + { + exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl])); + } + if (yieldProc == null) + { + List inputs = new List(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + var domain = linearTypeChecker.linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); + inputs.Add(f); + } + foreach (IdentifierExpr ie in globalMods) + { + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); + inputs.Add(f); + } + yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List(), inputs, new List(), new List(), new List(), new List()); + yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + } + CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List()); + yieldCallCmd.Proc = yieldProc; + return yieldCallCmd; + } + + private void AddCallToYieldProc(IToken tok, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) + { + if (!CommandLineOptions.Clo.TrustNonInterference) + { + CallCmd yieldCallCmd = CallToYieldProc(tok, ogOldGlobalMap, domainNameToLocalVar); + newCmds.Add(yieldCallCmd); + } + + if (pc != null) + { + Expr aa = OldEqualityExprForGlobals(ogOldGlobalMap); + Expr bb = OldEqualityExpr(ogOldGlobalMap); + + // assert pc || g_old == g || beta(i, g_old, o, g); + Expr assertExpr = Expr.Or(Expr.Ident(pc), Expr.Or(aa, beta)); + assertExpr.Typecheck(new TypecheckingContext(null)); + AssertCmd skipOrBetaAssertCmd = new AssertCmd(tok, assertExpr); + skipOrBetaAssertCmd.ErrorData = "Transition invariant in initial state violated"; + newCmds.Add(skipOrBetaAssertCmd); + + // assert pc ==> o_old == o && g_old == g; + assertExpr = Expr.Imp(Expr.Ident(pc), bb); + assertExpr.Typecheck(new TypecheckingContext(null)); + AssertCmd skipAssertCmd = new AssertCmd(tok, assertExpr); + skipAssertCmd.ErrorData = "Transition invariant in final state violated"; ; + newCmds.Add(skipAssertCmd); + + // pc, ok := g_old == g ==> pc, ok || beta(i, g_old, o, g); + List pcUpdateLHS = new List( + new AssignLhs[] { + new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)), + new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok)) + }); + List pcUpdateRHS = new List( + new Expr[] { + Expr.Imp(aa, Expr.Ident(pc)), + Expr.Or(Expr.Ident(ok), beta) + }); + foreach (Expr e in pcUpdateRHS) + { + e.Typecheck(new TypecheckingContext(null)); + } + newCmds.Add(new AssignCmd(Token.NoToken, pcUpdateLHS, pcUpdateRHS)); + } + } + + private Dictionary ComputeAvailableExprs(IEnumerable availableLinearVars, Dictionary domainNameToInputVar) + { + Dictionary domainNameToExpr = new Dictionary(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + var expr = Expr.Ident(domainNameToInputVar[domainName]); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + foreach (Variable v in availableLinearVars) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + var domain = linearTypeChecker.linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + return domainNameToExpr; + } + + private void AddUpdatesToOldGlobalVars(List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar, Dictionary domainNameToExpr) + { + List lhss = new List(); + List rhss = new List(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); + rhss.Add(domainNameToExpr[domainName]); + } + foreach (Variable g in ogOldGlobalMap.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); + rhss.Add(Expr.Ident(g)); + } + if (lhss.Count > 0) + { + newCmds.Add(new AssignCmd(Token.NoToken, lhss, rhss)); + } + } + + private Expr OldEqualityExpr(Dictionary ogOldGlobalMap) + { + Expr bb = Expr.True; + foreach (Variable o in ogOldGlobalMap.Keys) + { + if (o is GlobalVariable && !frame.Contains(o)) continue; + bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); + bb.Type = Type.Bool; + } + return bb; + } + + private Expr OldEqualityExprForGlobals(Dictionary ogOldGlobalMap) + { + Expr bb = Expr.True; + foreach (Variable o in ogOldGlobalMap.Keys) + { + if (o is GlobalVariable && frame.Contains(o)) + { + bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); + bb.Type = Type.Bool; + } + } + return bb; + } + + private void DesugarYield(YieldCmd yieldCmd, List cmds, List newCmds, Dictionary ogOldGlobalMap, Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar) + { + AddCallToYieldProc(yieldCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + + if (globalMods.Count > 0) + { + newCmds.Add(new HavocCmd(Token.NoToken, globalMods)); + if (pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + } + + Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(yieldCmd), domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + + for (int j = 0; j < cmds.Count; j++) + { + PredicateCmd predCmd = (PredicateCmd)cmds[j]; + newCmds.Add(new AssumeCmd(Token.NoToken, predCmd.Expr)); + } + } + + public void DesugarParallelCallCmd(List newCmds, ParCallCmd parCallCmd) + { + List parallelCalleeNames = new List(); + List ins = new List(); + List outs = new List(); + string procName = "og"; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + procName = procName + "_" + callCmd.Proc.Name; + ins.AddRange(callCmd.Ins); + outs.AddRange(callCmd.Outs); + } + Procedure proc; + if (asyncAndParallelCallDesugarings.ContainsKey(procName)) + { + proc = asyncAndParallelCallDesugarings[procName]; + } + else + { + List inParams = new List(); + List outParams = new List(); + List requiresSeq = new List(); + List ensuresSeq = new List(); + int count = 0; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + Dictionary map = new Dictionary(); + foreach (Variable x in callCmd.Proc.InParams) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true); + inParams.Add(y); + map[x] = Expr.Ident(y); + } + foreach (Variable x in callCmd.Proc.OutParams) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false); + outParams.Add(y); + map[x] = Expr.Ident(y); + } + Contract.Assume(callCmd.Proc.TypeParameters.Count == 0); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (Requires req in callCmd.Proc.Requires) + { + requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes)); + } + foreach (Ensures ens in callCmd.Proc.Ensures) + { + ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes)); + } + count++; + } + proc = new Procedure(Token.NoToken, procName, new List(), inParams, outParams, requiresSeq, globalMods, ensuresSeq); + asyncAndParallelCallDesugarings[procName] = proc; + } + CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes); + dummyCallCmd.Proc = proc; + newCmds.Add(dummyCallCmd); + } + + private void CreateYieldCheckerImpl(Implementation impl, List> yields) + { + if (yields.Count == 0) return; + + Dictionary map = new Dictionary(); + foreach (Variable local in impl.LocVars) + { + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type)); + map[local] = Expr.Ident(copy); + } + + Program program = linearTypeChecker.program; + List locals = new List(); + List inputs = new List(); + foreach (IdentifierExpr ie in map.Values) + { + locals.Add(ie.Decl); + } + for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) + { + Variable inParam = impl.InParams[i]; + Variable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type)); + locals.Add(copy); + map[impl.InParams[i]] = Expr.Ident(copy); + } + { + int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + Variable inParam = impl.InParams[i]; + Variable copy = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type), true); + inputs.Add(copy); + map[impl.InParams[i]] = Expr.Ident(copy); + i++; + } + } + for (int i = 0; i < impl.OutParams.Count; i++) + { + Variable outParam = impl.OutParams[i]; + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, outParam.Name, outParam.TypedIdent.Type)); + locals.Add(copy); + map[impl.OutParams[i]] = Expr.Ident(copy); + } + Dictionary ogOldLocalMap = new Dictionary(); + Dictionary assumeMap = new Dictionary(map); + foreach (IdentifierExpr ie in globalMods) + { + Variable g = ie.Decl; + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_local_old_{0}", g.Name), g.TypedIdent.Type)); + locals.Add(copy); + ogOldLocalMap[g] = Expr.Ident(copy); + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type), true); + inputs.Add(f); + assumeMap[g] = Expr.Ident(f); + } + + Substitution assumeSubst = Substituter.SubstitutionFromHashtable(assumeMap); + Substitution oldSubst = Substituter.SubstitutionFromHashtable(ogOldLocalMap); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + List yieldCheckerBlocks = new List(); + List labels = new List(); + List labelTargets = new List(); + Block yieldCheckerBlock = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); + labels.Add(yieldCheckerBlock.Label); + labelTargets.Add(yieldCheckerBlock); + yieldCheckerBlocks.Add(yieldCheckerBlock); + int yieldCount = 0; + foreach (List cs in yields) + { + List newCmds = new List(); + foreach (Cmd cmd in cs) + { + PredicateCmd predCmd = (PredicateCmd)cmd; + newCmds.Add(new AssumeCmd(Token.NoToken, Substituter.ApplyReplacingOldExprs(assumeSubst, oldSubst, predCmd.Expr))); + } + foreach (Cmd cmd in cs) + { + PredicateCmd predCmd = (PredicateCmd)cmd; + var newExpr = Substituter.ApplyReplacingOldExprs(subst, oldSubst, predCmd.Expr); + if (predCmd is AssertCmd) + { + AssertCmd assertCmd = new AssertCmd(predCmd.tok, newExpr, predCmd.Attributes); + assertCmd.ErrorData = "Non-interference check failed"; + newCmds.Add(assertCmd); + } + else + { + newCmds.Add(new AssumeCmd(Token.NoToken, newExpr)); + } + } + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + yieldCheckerBlock = new Block(Token.NoToken, "L" + yieldCount++, newCmds, new ReturnCmd(Token.NoToken)); + labels.Add(yieldCheckerBlock.Label); + labelTargets.Add(yieldCheckerBlock); + yieldCheckerBlocks.Add(yieldCheckerBlock); + } + yieldCheckerBlocks.Insert(0, new Block(Token.NoToken, "enter", new List(), new GotoCmd(Token.NoToken, labels, labelTargets))); + + // Create the yield checker procedure + var yieldCheckerName = string.Format("{0}_YieldChecker_{1}", "Impl", impl.Name); + var yieldCheckerProc = new Procedure(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), new List(), new List(), new List()); + yieldCheckerProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + yieldCheckerProcs.Add(yieldCheckerProc); + + // Create the yield checker implementation + var yieldCheckerImpl = new Implementation(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List(), locals, yieldCheckerBlocks); + yieldCheckerImpl.Proc = yieldCheckerProc; + yieldCheckerImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + yieldCheckerImpls.Add(yieldCheckerImpl); + } + + private bool IsYieldingHeader(Graph graph, Block header) + { + foreach (Block backEdgeNode in graph.BackEdgeNodes(header)) + { + foreach (Block x in graph.NaturalLoops(header, backEdgeNode)) + { + foreach (Cmd cmd in x.Cmds) + { + if (cmd is YieldCmd) + return true; + if (cmd is ParCallCmd) + return true; + CallCmd callCmd = cmd as CallCmd; + if (callCmd == null) continue; + if (yieldingProcs.Contains(callCmd.Proc)) + return true; + } + } + } + return false; + } + + private Graph ComputeYieldingLoopHeaders(Implementation impl, out HashSet yieldingHeaders) + { + Graph graph; + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + graph = Program.GraphFromImpl(impl); + graph.ComputeLoops(); + if (!graph.Reducible) + { + throw new Exception("Irreducible flow graphs are unsupported."); + } + yieldingHeaders = new HashSet(); + IEnumerable sortedHeaders = graph.SortHeadersByDominance(); + foreach (Block header in sortedHeaders) + { + if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) + { + yieldingHeaders.Add(header); + } + else if (IsYieldingHeader(graph, header)) + { + yieldingHeaders.Add(header); + } + else + { + continue; + } + } + return graph; + } + + private void SetupRefinementCheck(Implementation impl, + out List newLocalVars, + out Dictionary domainNameToInputVar, out Dictionary domainNameToLocalVar, out Dictionary ogOldGlobalMap) + { + pc = null; + ok = null; + alpha = null; + beta = null; + frame = null; + + newLocalVars = new List(); + Program program = linearTypeChecker.program; + ogOldGlobalMap = new Dictionary(); + foreach (IdentifierExpr ie in globalMods) + { + Variable g = ie.Decl; + LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type)); + ogOldGlobalMap[g] = l; + newLocalVars.Add(l); + } + + Procedure originalProc = implMap[impl].Proc; + ActionInfo actionInfo = moverTypeChecker.procToActionInfo[originalProc]; + if (actionInfo.createdAtLayerNum == this.layerNum) + { + pc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_pc", Type.Bool)); + newLocalVars.Add(pc); + ok = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_ok", Type.Bool)); + newLocalVars.Add(ok); + Dictionary alwaysMap = new Dictionary(); + for (int i = 0; i < originalProc.InParams.Count; i++) + { + alwaysMap[originalProc.InParams[i]] = Expr.Ident(impl.InParams[i]); + } + for (int i = 0; i < originalProc.OutParams.Count; i++) + { + alwaysMap[originalProc.OutParams[i]] = Expr.Ident(impl.OutParams[i]); + } + Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap); + Dictionary foroldMap = new Dictionary(); + foreach (IdentifierExpr ie in globalMods) + { + foroldMap[ie.Decl] = Expr.Ident(ogOldGlobalMap[ie.Decl]); + } + Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap); + frame = new HashSet(moverTypeChecker.SharedVariables); + HashSet introducedVars = new HashSet(); + foreach (Variable v in moverTypeChecker.SharedVariables) + { + if (moverTypeChecker.globalVarToSharedVarInfo[v].hideLayerNum <= actionInfo.createdAtLayerNum || + moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum > actionInfo.createdAtLayerNum) + { + frame.Remove(v); + } + if (moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum == actionInfo.createdAtLayerNum) + { + introducedVars.Add(v); + } + } + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo == null) + { + beta = Expr.True; + foreach (var v in frame) + { + beta = Expr.And(beta, Expr.Eq(Expr.Ident(v), foroldMap[v])); + } + alpha = Expr.True; + } + else + { + Expr betaExpr = (new MoverCheck.TransitionRelationComputation(moverTypeChecker.program, atomicActionInfo, frame, introducedVars)).TransitionRelationCompute(true); + beta = Substituter.ApplyReplacingOldExprs(always, forold, betaExpr); + Expr alphaExpr = Expr.True; + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + alphaExpr = Expr.And(alphaExpr, assertCmd.Expr); + alphaExpr.Type = Type.Bool; + } + alpha = Substituter.Apply(always, alphaExpr); + } + foreach (Variable f in impl.OutParams) + { + LocalVariable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_old_{0}", f.Name), f.TypedIdent.Type)); + newLocalVars.Add(copy); + ogOldGlobalMap[f] = copy; + } + } + + domainNameToInputVar = new Dictionary(); + domainNameToLocalVar = new Dictionary(); + { + int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + Variable inParam = impl.InParams[i]; + domainNameToInputVar[domainName] = inParam; + Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type)); + domainNameToLocalVar[domainName] = l; + newLocalVars.Add(l); + i++; + } + } + } + + private void TransformImpl(Implementation impl) + { + HashSet yieldingHeaders; + Graph graph = ComputeYieldingLoopHeaders(impl, out yieldingHeaders); + + List newLocalVars; + Dictionary domainNameToInputVar, domainNameToLocalVar; + Dictionary ogOldGlobalMap; + SetupRefinementCheck(impl, out newLocalVars, out domainNameToInputVar, out domainNameToLocalVar, out ogOldGlobalMap); + + List> yields = CollectAndDesugarYields(impl, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); + + List oldPcs, oldOks; + ProcessLoopHeaders(impl, graph, yieldingHeaders, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap, out oldPcs, out oldOks); + + AddInitialBlock(impl, oldPcs, oldOks, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); + + CreateYieldCheckerImpl(impl, yields); + + impl.LocVars.AddRange(newLocalVars); + impl.LocVars.AddRange(oldPcs); + impl.LocVars.AddRange(oldOks); + + UnifyCallsToYieldProc(impl, ogOldGlobalMap, domainNameToLocalVar); + } + + private void UnifyCallsToYieldProc(Implementation impl, Dictionary ogOldGlobalMap, Dictionary domainNameToLocalVar) + { + CallCmd yieldCallCmd = CallToYieldProc(Token.NoToken, ogOldGlobalMap, domainNameToLocalVar); + Block yieldCheckBlock = new Block(Token.NoToken, "CallToYieldProc", new List(new Cmd[] { yieldCallCmd, new AssumeCmd(Token.NoToken, Expr.False) }), new ReturnCmd(Token.NoToken)); + List newBlocks = new List(); + foreach (Block b in impl.Blocks) + { + TransferCmd transferCmd = b.TransferCmd; + List newCmds = new List(); + for (int i = b.Cmds.Count-1; i >= 0; i--) + { + CallCmd callCmd = b.Cmds[i] as CallCmd; + if (callCmd == null || callCmd.Proc != yieldProc) + { + newCmds.Insert(0, b.Cmds[i]); + } + else + { + Block newBlock = new Block(Token.NoToken, b.Label + i, newCmds, transferCmd); + newCmds = new List(); + transferCmd = new GotoCmd(Token.NoToken, new List(new string[] { newBlock.Label, yieldCheckBlock.Label }), + new List(new Block[] { newBlock, yieldCheckBlock })); + newBlocks.Add(newBlock); + } + } + b.Cmds = newCmds; + b.TransferCmd = transferCmd; + } + impl.Blocks.AddRange(newBlocks); + impl.Blocks.Add(yieldCheckBlock); + } + + private List> CollectAndDesugarYields(Implementation impl, + Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) + { + // Collect the yield predicates and desugar yields + List> yields = new List>(); + List cmds = new List(); + foreach (Block b in impl.Blocks) + { + YieldCmd yieldCmd = null; + List newCmds = new List(); + for (int i = 0; i < b.Cmds.Count; i++) + { + Cmd cmd = b.Cmds[i]; + if (cmd is YieldCmd) + { + yieldCmd = (YieldCmd)cmd; + continue; + } + if (yieldCmd != null) + { + PredicateCmd pcmd = cmd as PredicateCmd; + if (pcmd == null) + { + DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); + if (cmds.Count > 0) + { + yields.Add(cmds); + cmds = new List(); + } + yieldCmd = null; + } + else + { + cmds.Add(pcmd); + } + } + + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (yieldingProcs.Contains(callCmd.Proc)) + { + AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + } + if (callCmd.IsAsync) + { + if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) + { + asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List(), new List()); + } + var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; + CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes); + dummyCallCmd.Proc = dummyAsyncTargetProc; + newCmds.Add(dummyCallCmd); + } + else + { + newCmds.Add(callCmd); + } + if (yieldingProcs.Contains(callCmd.Proc)) + { + HashSet availableLinearVars = new HashSet(AvailableLinearVars(callCmd)); + linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); + + if (!callCmd.IsAsync && globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + + Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = cmd as ParCallCmd; + AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + DesugarParallelCallCmd(newCmds, parCallCmd); + HashSet availableLinearVars = new HashSet(AvailableLinearVars(parCallCmd)); + linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); + + if (globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + + Dictionary domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + else + { + newCmds.Add(cmd); + } + } + if (yieldCmd != null) + { + DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); + if (cmds.Count > 0) + { + yields.Add(cmds); + cmds = new List(); + } + } + if (b.TransferCmd is ReturnCmd) + { + AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + if (pc != null) + { + AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok)); + assertCmd.ErrorData = "Failed to execute atomic action before procedure return"; + newCmds.Add(assertCmd); + } + } + b.Cmds = newCmds; + } + return yields; + } + + private void ProcessLoopHeaders(Implementation impl, Graph graph, HashSet yieldingHeaders, + Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap, + out List oldPcs, out List oldOks) + { + oldPcs = new List(); + oldOks = new List(); + foreach (Block header in yieldingHeaders) + { + LocalVariable oldPc = null; + LocalVariable oldOk = null; + if (pc != null) + { + oldPc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", pc.Name, header.Label), Type.Bool)); + oldPcs.Add(oldPc); + oldOk = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", ok.Name, header.Label), Type.Bool)); + oldOks.Add(oldOk); + } + Dictionary domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar); + foreach (Block pred in header.Predecessors) + { + AddCallToYieldProc(header.tok, pred.Cmds, ogOldGlobalMap, domainNameToLocalVar); + if (pc != null && !graph.BackEdgeNodes(header).Contains(pred)) + { + pred.Cmds.Add(new AssignCmd(Token.NoToken, new List( + new AssignLhs[] { new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)), new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)) }), + new List(new Expr[] { Expr.Ident(pc), Expr.Ident(ok) }))); + } + AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + List newCmds = new List(); + if (pc != null) + { + AssertCmd assertCmd; + assertCmd = new AssertCmd(header.tok, Expr.Eq(Expr.Ident(oldPc), Expr.Ident(pc))); + assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; + newCmds.Add(assertCmd); + assertCmd = new AssertCmd(header.tok, Expr.Imp(Expr.Ident(oldOk), Expr.Ident(ok))); + assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; + newCmds.Add(assertCmd); + } + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName]))); + } + foreach (Variable v in ogOldGlobalMap.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(v), Expr.Ident(ogOldGlobalMap[v])))); + } + newCmds.AddRange(header.Cmds); + header.Cmds = newCmds; + } + } + + private void AddInitialBlock(Implementation impl, List oldPcs, List oldOks, + Dictionary domainNameToInputVar, Dictionary domainNameToLocalVar, Dictionary ogOldGlobalMap) + { + // Add initial block + List lhss = new List(); + List rhss = new List(); + if (pc != null) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc))); + rhss.Add(Expr.False); + foreach (Variable oldPc in oldPcs) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc))); + rhss.Add(Expr.False); + } + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok))); + rhss.Add(Expr.False); + foreach (Variable oldOk in oldOks) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk))); + rhss.Add(Expr.False); + } + } + Dictionary domainNameToExpr = new Dictionary(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); + } + for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) + { + Variable v = impl.InParams[i]; + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + var domain = linearTypeChecker.linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); + } + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); + rhss.Add(domainNameToExpr[domainName]); + } + foreach (Variable g in ogOldGlobalMap.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); + rhss.Add(Expr.Ident(g)); + } + if (lhss.Count > 0) + { + Block initBlock = new Block(Token.NoToken, "og_init", new List { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List { impl.Blocks[0].Label }, new List { impl.Blocks[0] })); + impl.Blocks.Insert(0, initBlock); + } + } + + private void AddYieldProcAndImpl(List decls) + { + if (yieldProc == null) return; + + Program program = linearTypeChecker.program; + List inputs = new List(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + var domain = linearTypeChecker.linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); + inputs.Add(f); + } + foreach (IdentifierExpr ie in globalMods) + { + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); + inputs.Add(f); + } + List blocks = new List(); + TransferCmd transferCmd = new ReturnCmd(Token.NoToken); + if (yieldCheckerProcs.Count > 0) + { + List blockTargets = new List(); + List labelTargets = new List(); + int labelCount = 0; + foreach (Procedure proc in yieldCheckerProcs) + { + List exprSeq = new List(); + foreach (Variable v in inputs) + { + exprSeq.Add(Expr.Ident(v)); + } + CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List()); + callCmd.Proc = proc; + string label = string.Format("L_{0}", labelCount++); + Block block = new Block(Token.NoToken, label, new List { callCmd }, new ReturnCmd(Token.NoToken)); + labelTargets.Add(label); + blockTargets.Add(block); + blocks.Add(block); + } + transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets); + } + blocks.Insert(0, new Block(Token.NoToken, "enter", new List(), transferCmd)); + + var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List(), inputs, new List(), new List(), blocks); + yieldImpl.Proc = yieldProc; + yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + decls.Add(yieldProc); + decls.Add(yieldImpl); + } + + public static QKeyValue RemoveYieldsAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveYieldsAttribute(iter.Next); + return (iter.Key == "yields") ? iter.Next : iter; + } + + public static QKeyValue RemoveMoverAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveMoverAttribute(iter.Next); + if (iter.Key == "atomic" || iter.Key == "right" || iter.Key == "left" || iter.Key == "both") + return iter.Next; + else + return iter; + } + + private List Collect() + { + List decls = new List(); + foreach (Procedure proc in yieldCheckerProcs) + { + decls.Add(proc); + } + foreach (Implementation impl in yieldCheckerImpls) + { + decls.Add(impl); + } + foreach (Procedure proc in asyncAndParallelCallDesugarings.Values) + { + decls.Add(proc); + } + AddYieldProcAndImpl(decls); + return decls; + } + + public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List decls) + { + Program program = linearTypeChecker.program; + foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum })) + { + if (CommandLineOptions.Clo.TrustLayersDownto <= layerNum || layerNum <= CommandLineOptions.Clo.TrustLayersUpto) continue; + + MyDuplicator duplicator = new MyDuplicator(moverTypeChecker, layerNum); + foreach (var proc in program.Procedures) + { + if (!moverTypeChecker.procToActionInfo.ContainsKey(proc)) continue; + Procedure duplicateProc = duplicator.VisitProcedure(proc); + decls.Add(duplicateProc); + } + decls.AddRange(duplicator.impls); + OwickiGries ogTransform = new OwickiGries(linearTypeChecker, moverTypeChecker, duplicator); + foreach (var impl in program.Implementations) + { + if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc) || moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum < layerNum) + continue; + Implementation duplicateImpl = duplicator.VisitImplementation(impl); + ogTransform.TransformImpl(duplicateImpl); + decls.Add(duplicateImpl); + } + decls.AddRange(ogTransform.Collect()); + } + } + } +} diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs index 542d3515..c821117a 100644 --- a/Source/Concurrency/TypeCheck.cs +++ b/Source/Concurrency/TypeCheck.cs @@ -49,6 +49,8 @@ namespace Microsoft.Boogie { public Ensures ensures; public MoverType moverType; + public List gate; + public CodeExpr action; public List thisGate; public CodeExpr thisAction; public List thisInParams; @@ -61,6 +63,8 @@ namespace Microsoft.Boogie public HashSet modifiedGlobalVars; public HashSet gateUsedGlobalVars; public bool hasAssumeCmd; + public Dictionary thisMap; + public Dictionary thatMap; public bool CommutesWith(AtomicActionInfo actionInfo) { @@ -84,122 +88,137 @@ namespace Microsoft.Boogie public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum) : base(proc, layerNum, availableUptoLayerNum) { - CodeExpr codeExpr = ensures.Condition as CodeExpr; this.ensures = ensures; this.moverType = moverType; + this.gate = new List(); + this.action = ensures.Condition as CodeExpr; this.thisGate = new List(); - this.thisAction = codeExpr; this.thisInParams = new List(); this.thisOutParams = new List(); this.thatGate = new List(); this.thatInParams = new List(); this.thatOutParams = new List(); this.hasAssumeCmd = false; - - foreach (Block block in codeExpr.Blocks) + this.thisMap = new Dictionary(); + this.thatMap = new Dictionary(); + + foreach (Block block in this.action.Blocks) { block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd); } - var cmds = thisAction.Blocks[0].Cmds; + foreach (Block block in this.action.Blocks) + { + if (block.TransferCmd is ReturnExprCmd) + { + block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); + } + } + + var cmds = this.action.Blocks[0].Cmds; for (int i = 0; i < cmds.Count; i++) { AssertCmd assertCmd = cmds[i] as AssertCmd; if (assertCmd == null) break; - thisGate.Add(assertCmd); + this.gate.Add(assertCmd); cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True); } - Dictionary map = new Dictionary(); foreach (Variable x in proc.InParams) { - this.thisInParams.Add(x); - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); - this.thatInParams.Add(y); - map[x] = Expr.Ident(y); + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thisInParams.Add(thisx); + this.thisMap[x] = Expr.Ident(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thatInParams.Add(thatx); + this.thatMap[x] = Expr.Ident(thatx); } foreach (Variable x in proc.OutParams) { - this.thisOutParams.Add(x); - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); - this.thatOutParams.Add(y); - map[x] = Expr.Ident(y); + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thisOutParams.Add(thisx); + this.thisMap[x] = Expr.Ident(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thatOutParams.Add(thatx); + this.thatMap[x] = Expr.Ident(thatx); } + List thisLocVars = new List(); List thatLocVars = new List(); - foreach (Variable x in thisAction.LocVars) + foreach (Variable x in this.action.LocVars) { - Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); - map[x] = Expr.Ident(y); - thatLocVars.Add(y); + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), false); + thisMap[x] = Expr.Ident(thisx); + thisLocVars.Add(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); + thatMap[x] = Expr.Ident(thatx); + thatLocVars.Add(thatx); } Contract.Assume(proc.TypeParameters.Count == 0); - Substitution subst = Substituter.SubstitutionFromHashtable(map); - foreach (AssertCmd assertCmd in thisGate) + Substitution thisSubst = Substituter.SubstitutionFromHashtable(this.thisMap); + Substitution thatSubst = Substituter.SubstitutionFromHashtable(this.thatMap); + foreach (AssertCmd assertCmd in this.gate) + { + this.thisGate.Add((AssertCmd)Substituter.Apply(thisSubst, assertCmd)); + this.thatGate.Add((AssertCmd)Substituter.Apply(thatSubst, assertCmd)); + } + this.thisAction = new CodeExpr(thisLocVars, SubstituteBlocks(this.action.Blocks, thisSubst, "this_")); + this.thatAction = new CodeExpr(thatLocVars, SubstituteBlocks(this.action.Blocks, thatSubst, "that_")); + { - thatGate.Add((AssertCmd)Substituter.Apply(subst, assertCmd)); + VariableCollector collector = new VariableCollector(); + collector.Visit(this.action); + this.actionUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); } + + List modifiedVars = new List(); + foreach (Block block in this.action.Blocks) + { + block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); + } + this.modifiedGlobalVars = new HashSet(modifiedVars.Where(x => x is GlobalVariable)); + + { + VariableCollector collector = new VariableCollector(); + this.gate.ForEach(assertCmd => collector.Visit(assertCmd)); + this.gateUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); + } + } + + private List SubstituteBlocks(List blocks, Substitution subst, string blockLabelPrefix) + { Dictionary blockMap = new Dictionary(); - List thatBlocks = new List(); - foreach (Block block in thisAction.Blocks) + List otherBlocks = new List(); + foreach (Block block in blocks) { List otherCmds = new List(); foreach (Cmd cmd in block.Cmds) { otherCmds.Add(Substituter.Apply(subst, cmd)); } - Block thatBlock = new Block(); - thatBlock.Cmds = otherCmds; - thatBlock.Label = "that_" + block.Label; - block.Label = "this_" + block.Label; - thatBlocks.Add(thatBlock); - blockMap[block] = thatBlock; - if (block.TransferCmd is GotoCmd) - { - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - for (int i = 0; i < gotoCmd.labelNames.Count; i++) - { - gotoCmd.labelNames[i] = "this_" + gotoCmd.labelNames[i]; - } - } + Block otherBlock = new Block(); + otherBlock.Cmds = otherCmds; + otherBlock.Label = blockLabelPrefix + block.Label; + otherBlocks.Add(otherBlock); + blockMap[block] = otherBlock; } - foreach (Block block in thisAction.Blocks) + foreach (Block block in blocks) { - if (block.TransferCmd is ReturnExprCmd) + if (block.TransferCmd is ReturnCmd) { - block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok); continue; } - List thatGotoCmdLabelTargets = new List(); - List thatGotoCmdLabelNames = new List(); + List otherGotoCmdLabelTargets = new List(); + List otherGotoCmdLabelNames = new List(); GotoCmd gotoCmd = block.TransferCmd as GotoCmd; foreach (Block target in gotoCmd.labelTargets) { - thatGotoCmdLabelTargets.Add(blockMap[target]); - thatGotoCmdLabelNames.Add(blockMap[target].Label); + otherGotoCmdLabelTargets.Add(blockMap[target]); + otherGotoCmdLabelNames.Add(blockMap[target].Label); } - blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, thatGotoCmdLabelNames, thatGotoCmdLabelTargets); - } - this.thatAction = new CodeExpr(thatLocVars, thatBlocks); - - { - VariableCollector collector = new VariableCollector(); - collector.Visit(codeExpr); - this.actionUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); - } - - List modifiedVars = new List(); - foreach (Block block in codeExpr.Blocks) - { - block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); - } - this.modifiedGlobalVars = new HashSet(modifiedVars.Where(x => x is GlobalVariable)); - - { - VariableCollector collector = new VariableCollector(); - this.thisGate.ForEach(assertCmd => collector.Visit(assertCmd)); - this.gateUsedGlobalVars = new HashSet(collector.usedVars.Where(x => x is GlobalVariable)); + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); } + return otherBlocks; } } diff --git a/Test/civl/bar.bpl.expect b/Test/civl/bar.bpl.expect index 8999ae7f..810c93bf 100644 --- a/Test/civl/bar.bpl.expect +++ b/Test/civl/bar.bpl.expect @@ -1,13 +1,13 @@ -bar.bpl(28,3): Error: Non-interference check failed -Execution trace: - bar.bpl(7,3): anon0 - (0,0): anon00 - bar.bpl(14,3): inline$Incr_1$0$this_A - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 -bar.bpl(28,3): Error: Non-interference check failed -Execution trace: - bar.bpl(38,3): anon0 - (0,0): anon00 - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 - -Boogie program verifier finished with 3 verified, 2 errors +bar.bpl(28,3): Error: Non-interference check failed +Execution trace: + bar.bpl(7,3): anon0 + (0,0): anon00 + bar.bpl(14,3): inline$Incr_1$0$A + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 +bar.bpl(28,3): Error: Non-interference check failed +Execution trace: + bar.bpl(38,3): anon0 + (0,0): anon00 + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 + +Boogie program verifier finished with 3 verified, 2 errors diff --git a/Test/civl/foo.bpl.expect b/Test/civl/foo.bpl.expect index 0d9de9db..41e30691 100644 --- a/Test/civl/foo.bpl.expect +++ b/Test/civl/foo.bpl.expect @@ -1,8 +1,8 @@ -foo.bpl(30,3): Error: Non-interference check failed -Execution trace: - foo.bpl(7,3): anon0 - (0,0): anon00 - foo.bpl(14,3): inline$Incr_1$0$this_A - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 - -Boogie program verifier finished with 4 verified, 1 error +foo.bpl(30,3): Error: Non-interference check failed +Execution trace: + foo.bpl(7,3): anon0 + (0,0): anon00 + foo.bpl(14,3): inline$Incr_1$0$A + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 + +Boogie program verifier finished with 4 verified, 1 error diff --git a/Test/civl/parallel1.bpl.expect b/Test/civl/parallel1.bpl.expect index 588c9c5b..889ee4f2 100644 --- a/Test/civl/parallel1.bpl.expect +++ b/Test/civl/parallel1.bpl.expect @@ -1,8 +1,8 @@ -parallel1.bpl(30,3): Error: Non-interference check failed -Execution trace: - parallel1.bpl(7,3): anon0 - (0,0): anon00 - parallel1.bpl(14,3): inline$Incr_1$0$this_A - (0,0): inline$Impl_YieldChecker_PC_1$0$L0 - -Boogie program verifier finished with 3 verified, 1 error +parallel1.bpl(30,3): Error: Non-interference check failed +Execution trace: + parallel1.bpl(7,3): anon0 + (0,0): anon00 + parallel1.bpl(14,3): inline$Incr_1$0$A + (0,0): inline$Impl_YieldChecker_PC_1$0$L0 + +Boogie program verifier finished with 3 verified, 1 error diff --git a/Test/civl/t1.bpl.expect b/Test/civl/t1.bpl.expect index 0b0c936e..fcef7e58 100644 --- a/Test/civl/t1.bpl.expect +++ b/Test/civl/t1.bpl.expect @@ -1,9 +1,9 @@ -t1.bpl(65,5): Error: Non-interference check failed -Execution trace: - t1.bpl(84,13): anon0 - (0,0): anon05 - (0,0): inline$SetG_1$0$Entry - t1.bpl(25,21): inline$SetG_1$0$this_A - (0,0): inline$Impl_YieldChecker_A_1$0$L1 - -Boogie program verifier finished with 4 verified, 1 error +t1.bpl(65,5): Error: Non-interference check failed +Execution trace: + t1.bpl(84,13): anon0 + (0,0): anon05 + (0,0): inline$SetG_1$0$Entry + t1.bpl(25,21): inline$SetG_1$0$A + (0,0): inline$Impl_YieldChecker_A_1$0$L1 + +Boogie program verifier finished with 4 verified, 1 error -- cgit v1.2.3 From d0f2ef8050f0fa2ed6315bc6fd448ee558420d75 Mon Sep 17 00:00:00 2001 From: qadeer Date: Wed, 17 Jun 2015 20:46:44 -0700 Subject: added another sample --- Test/civl/StoreBuffer.bpl | 187 +++++++++++++++++++++++++++++++++++++++ Test/civl/StoreBuffer.bpl.expect | 2 + 2 files changed, 189 insertions(+) create mode 100644 Test/civl/StoreBuffer.bpl create mode 100644 Test/civl/StoreBuffer.bpl.expect diff --git a/Test/civl/StoreBuffer.bpl b/Test/civl/StoreBuffer.bpl new file mode 100644 index 00000000..d2d27ef9 --- /dev/null +++ b/Test/civl/StoreBuffer.bpl @@ -0,0 +1,187 @@ +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +function {:builtin "MapConst"} MapConstBool(bool) : [int]bool; + +function {:inline} {:linear "tid"} TidCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +function {:inline} {:linear "addr"} AddrCollector(x: int) : [int]bool +{ + MapConstBool(false)[x := true] +} + +const numMutators: int; +axiom 0 < numMutators; +function {:inline} mutatorTid(i: int) : bool { 1 <= i && i <= numMutators } + +const GcTid: int; +axiom numMutators < GcTid; +function {:inline} mutatorOrGcTid(i: int) : bool { (1 <= i && i <= numMutators) || i == GcTid } + +const lockAddr: int; +axiom 0 < lockAddr; +const collectorPhaseAddr: int; +axiom lockAddr < collectorPhaseAddr; + +var {:layer 0,1} Mem: [int]int; +var {:layer 0,1} StoreBufferVal: [int][int]int; +var {:layer 0,1} StoreBufferPresent: [int][int]bool; + +var {:layer 0} lock: int; +var {:layer 0} collectorPhase: int; +var {:layer 0} collectorPhaseDelayed: int; + +function {:inline} LockInv(StoreBufferPresent:[int][int]bool, StoreBufferVal:[int][int]int, Mem:[int]int, lock:int, collectorPhase:int, collectorPhaseDelayed:int): bool +{ + (Mem[lockAddr] == 0 <==> lock == 0) && + (forall i:int :: mutatorOrGcTid(i) && StoreBufferPresent[i][lockAddr] ==> StoreBufferVal[i][lockAddr] == 0) && + (forall i:int :: mutatorOrGcTid(i) ==> lock == i || StoreBufferPresent[i] == MapConstBool(false)) && + (Mem[collectorPhaseAddr] == collectorPhase || (exists i:int :: mutatorOrGcTid(i) && StoreBufferPresent[i][collectorPhaseAddr])) && + (forall i:int :: mutatorOrGcTid(i) && StoreBufferPresent[i][collectorPhaseAddr] ==> StoreBufferVal[i][collectorPhaseAddr] == collectorPhase) && + collectorPhaseDelayed == Mem[collectorPhaseAddr] +} + +// Layer 1 +procedure {:yields} {:layer 1} YieldLock() +requires {:expand} {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +{ + yield; + assert {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +} + +procedure {:yields} {:layer 1} YieldStoreBufferLockAddrPresent({:linear "tid"} tid:int) +requires {:layer 1} StoreBufferPresent[tid][lockAddr]; +ensures {:layer 1} StoreBufferPresent[tid][lockAddr]; +{ + yield; + assert {:layer 1} StoreBufferPresent[tid][lockAddr]; +} + +procedure {:yields} {:layer 1} YieldStoreBufferLockAddrAbsent({:linear "tid"} tid:int) +requires {:layer 1} !StoreBufferPresent[tid][lockAddr]; +ensures {:layer 1} !StoreBufferPresent[tid][lockAddr]; +{ + yield; + assert {:layer 1} !StoreBufferPresent[tid][lockAddr]; +} + +procedure {:yields} {:layer 1} LockAcquire({:linear "tid"} tid: int) +requires {:layer 1} mutatorOrGcTid(tid); +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:right} |{ A: assert mutatorOrGcTid(tid); assume lock == 0; lock := tid; return true; }|; +{ + var status:bool; + call YieldLock(); + while (true) + invariant {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); + { + call status := LockCAS(tid); + if (status) + { + call YieldLock(); + return; + } + call YieldLock(); + } + call YieldLock(); +} + +procedure {:yields} {:layer 1} LockRelease({:linear "tid"} tid:int) +requires {:layer 1} mutatorOrGcTid(tid); +requires {:layer 1} !StoreBufferPresent[tid][lockAddr]; +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} !StoreBufferPresent[tid][lockAddr]; +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:atomic} |{ A: assert mutatorOrGcTid(tid); assert lock == tid; lock := 0; return true; }|; +{ + par YieldLock() | YieldStoreBufferLockAddrAbsent(tid); + call LockZero(tid); + par YieldLock() | YieldStoreBufferLockAddrPresent(tid); + call FlushStoreBufferEntryForLock(tid); + par YieldLock() | YieldStoreBufferLockAddrAbsent(tid); +} + +procedure {:yields} {:layer 1} ReadCollectorPhaseLocked({:linear "tid"} tid: int) returns (phase: int) +requires {:layer 1} mutatorOrGcTid(tid); +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:atomic} |{ A: assert mutatorOrGcTid(tid); assert lock == tid; phase := collectorPhase; return true; }|; +{ + call YieldLock(); + call phase := PrimitiveRead(tid, collectorPhaseAddr); + call YieldLock(); +} + +procedure {:yields} {:layer 1} ReadCollectorPhaseUnlocked({:linear "tid"} tid: int) returns (phase: int) +requires {:layer 1} mutatorOrGcTid(tid); +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:atomic} |{ A: assert mutatorOrGcTid(tid); assert lock != tid; phase := collectorPhaseDelayed; return true; }|; +{ + call YieldLock(); + call phase := PrimitiveRead(tid, collectorPhaseAddr); + call YieldLock(); +} + +procedure {:yields} {:layer 1} SetCollectorPhase({:linear "tid"} tid: int, phase: int) +requires {:layer 1} mutatorOrGcTid(tid); +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:atomic} |{ A: assert mutatorOrGcTid(tid); assert lock == tid; assert collectorPhase == collectorPhaseDelayed; collectorPhase := phase; return true; }|; +{ + call YieldLock(); + call PrimitiveSetCollectorPhase(tid, phase); + call YieldLock(); +} + +procedure {:yields} {:layer 1} SyncCollectorPhase({:linear "tid"} tid: int) +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:atomic} |{ A: collectorPhaseDelayed := collectorPhase; return true; }|; +{ + call YieldLock(); + call FlushStoreBufferEntryForCollectorPhase(); + call YieldLock(); +} + +procedure {:yields} {:layer 1} Barrier({:linear "tid"} tid: int) +requires {:layer 1} mutatorOrGcTid(tid); +requires {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:layer 1} LockInv(StoreBufferPresent, StoreBufferVal, Mem, lock, collectorPhase, collectorPhaseDelayed); +ensures {:atomic} |{ A: assert mutatorOrGcTid(tid); assert lock == tid; assume collectorPhase == collectorPhaseDelayed; return true; }|; +{ + call YieldLock(); + call WaitForFlush(tid); + call YieldLock(); +} + +// Layer 0 +procedure {:yields} {:layer 0,1} LockCAS(tid: int) returns (status: bool); +ensures {:atomic} |{ A: goto B, C; + B: assume Mem[lockAddr] == 0; Mem[lockAddr] := 1; lock := tid; status := true; return true; + C: status := false; return true; + }|; + +procedure {:yields} {:layer 0,1} LockZero(tid: int); +ensures {:atomic} |{ A: assert !StoreBufferPresent[tid][lockAddr]; StoreBufferPresent[tid][lockAddr] := true; StoreBufferVal[tid][lockAddr] := 0; return true; }|; + +procedure {:yields} {:layer 0,1} FlushStoreBufferEntryForLock(tid: int); +ensures {:atomic} |{ A: assert StoreBufferPresent[tid][lockAddr]; assume StoreBufferPresent[tid] == MapConstBool(false)[lockAddr := true]; Mem[lockAddr] := StoreBufferVal[tid][lockAddr]; StoreBufferPresent[tid][lockAddr] := false; lock := 0; return true; }|; + +procedure {:yields} {:layer 0,1} PrimitiveRead(tid: int, addr: int) returns (val: int); +ensures {:atomic} |{ A: goto B, C; + B: assume StoreBufferPresent[tid][addr]; val := StoreBufferVal[tid][addr]; return true; + C: assume !StoreBufferPresent[tid][addr]; val := Mem[addr]; return true; }|; + +procedure {:yields} {:layer 0,1} PrimitiveSetCollectorPhase(tid: int, phase:int); +ensures {:atomic} |{ A: StoreBufferPresent[tid][collectorPhaseAddr] := true; StoreBufferVal[tid][collectorPhaseAddr] := phase; collectorPhase := phase; return true; }|; + +procedure {:yields} {:layer 0,1} FlushStoreBufferEntryForCollectorPhase(); +ensures {:atomic} |{ var tid:int; A: assume mutatorOrGcTid(tid) && StoreBufferPresent[tid][collectorPhaseAddr]; Mem[collectorPhaseAddr] := StoreBufferVal[tid][collectorPhaseAddr]; StoreBufferPresent[tid][collectorPhaseAddr] := false; collectorPhaseDelayed := Mem[collectorPhaseAddr]; return true; }|; + +procedure {:yields} {:layer 0,1} WaitForFlush(tid: int); +ensures {:atomic} |{ A: assume StoreBufferPresent[tid] == MapConstBool(false); return true; }|; diff --git a/Test/civl/StoreBuffer.bpl.expect b/Test/civl/StoreBuffer.bpl.expect new file mode 100644 index 00000000..8c74fe2e --- /dev/null +++ b/Test/civl/StoreBuffer.bpl.expect @@ -0,0 +1,2 @@ + +Boogie program verifier finished with 17 verified, 0 errors -- cgit v1.2.3 From 28946971c2b9c9466b3146c08ef87d48d40654c2 Mon Sep 17 00:00:00 2001 From: akashlal Date: Sat, 20 Jun 2015 09:18:25 -0700 Subject: Missing braces --- Source/Houdini/Houdini.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Houdini/Houdini.cs b/Source/Houdini/Houdini.cs index 986d0fff..acdb1ff4 100644 --- a/Source/Houdini/Houdini.cs +++ b/Source/Houdini/Houdini.cs @@ -519,8 +519,10 @@ namespace Microsoft.Boogie.Houdini { } if (GetCandidateWithoutConstant(consequent, candidates, out candidateConstant, out exprWithoutConstant)) - exprWithoutConstant = Expr.Imp(antecedent, exprWithoutConstant); - return true; + { + exprWithoutConstant = Expr.Imp(antecedent, exprWithoutConstant); + return true; + } } return false; } -- cgit v1.2.3 From c57ef72622ef4bfd23dd42c656582bf0f778e6ee Mon Sep 17 00:00:00 2001 From: akashlal Date: Sat, 20 Jun 2015 09:18:47 -0700 Subject: Fix for reading fixpoint back into boogie exprs --- Source/Provers/SMTLib/ProverInterface.cs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index 7e7f0cf6..0ff2efa7 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -597,7 +597,10 @@ namespace Microsoft.Boogie.SMTLib if(declHandler.var_map.ContainsKey(name)) return declHandler.var_map[name]; HandleProverError ("Prover error: unknown symbol:" + name); - throw new BadExprFromProver (); + //throw new BadExprFromProver (); + var v = gen.Variable(name, Type.Int); + bound.Add(name, v); + return v; } ArgGetter g = i => SExprToVCExpr (e [i], bound); ArgsGetter ga = () => e.Arguments.Select (x => SExprToVCExpr (x, bound)).ToArray (); @@ -612,10 +615,11 @@ namespace Microsoft.Boogie.SMTLib { var binds = e.Arguments[0]; var vcbinds = new List(); + var bound_copy = new Dictionary(bound); for (int i = 0; i < binds.Arguments.Count(); i++) { var bind = binds.Arguments[i]; - var symb = bind.Name; + var symb = StripCruft(bind.Name); var vcv = SExprToVar(bind); vcbinds.Add(vcv); bound[symb] = vcv; @@ -625,12 +629,7 @@ namespace Microsoft.Boogie.SMTLib body = gen.Forall(vcbinds, new List(), body); else body = gen.Exists(vcbinds, new List(), body); - for (int i = 0; i < binds.Arguments.Count(); i++) - { - var bind = binds.Arguments[i]; - var symb = bind.Name; - bound.Remove(symb); - } + bound = bound_copy; return body; } case "-" : // have to deal with unary case @@ -650,6 +649,7 @@ namespace Microsoft.Boogie.SMTLib bool expand_lets = true; var binds = e.Arguments[0]; var vcbinds = new List(); + var bound_copy = new Dictionary(bound); for(int i = 0; i < binds.Arguments.Count(); i++){ var bind = binds.Arguments[i]; var symb = bind.Name; @@ -663,11 +663,7 @@ namespace Microsoft.Boogie.SMTLib var body = g(1); if(!expand_lets) body = gen.Let(vcbinds,body); - for(int i = 0; i < binds.Arguments.Count(); i++){ - var bind = binds.Arguments[i]; - var symb = bind.Name; - bound.Remove (symb); - } + bound = bound_copy; return body; } -- cgit v1.2.3 From 909a72d218edd18c9374b2cd9cc3496e946fd4ee Mon Sep 17 00:00:00 2001 From: qadeer Date: Thu, 25 Jun 2015 13:14:17 -0700 Subject: updated with Serdar's changes --- Test/civl/Program5.bpl | 167 +++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 83 deletions(-) diff --git a/Test/civl/Program5.bpl b/Test/civl/Program5.bpl index d728b845..362a6d9d 100644 --- a/Test/civl/Program5.bpl +++ b/Test/civl/Program5.bpl @@ -1,83 +1,84 @@ -// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" -// RUN: %diff "%s.expect" "%t" -type Tid; -const unique nil: Tid; - -function {:inline} UNALLOC():int { 0 } -function {:inline} WHITE():int { 1 } -function {:inline} GRAY():int { 2 } -function {:inline} BLACK():int { 3 } -function {:inline} Unalloc(i:int) returns(bool) { i <= 0 } -function {:inline} White(i:int) returns(bool) { i == 1 } -function {:inline} Gray(i:int) returns(bool) { i == 2 } -function {:inline} Black(i:int) returns(bool) { i >= 3 } - -procedure {:yields} {:layer 2} YieldColorOnlyGetsDarker() -ensures {:layer 2} Color >= old(Color); -{ - yield; - assert {:layer 2} Color >= old(Color); -} - -procedure {:yields} {:layer 2,3} WriteBarrier({:linear "tid"} tid:Tid) -ensures {:atomic} |{ A: assert tid != nil; goto B, C; - B: assume White(Color); Color := GRAY(); return true; - C: assume !White(Color); return true;}|; -requires {:layer 2} Color >= WHITE(); -ensures {:layer 2} Color >= GRAY(); -{ - var colorLocal:int; - yield; - assert {:layer 2} Color >= WHITE(); - call colorLocal := GetColorNoLock(); - call YieldColorOnlyGetsDarker(); - if (White(colorLocal)) { call WriteBarrierSlow(tid); } - yield; - assert {:layer 2} Color >= GRAY(); -} - -procedure {:yields} {:layer 1,2} WriteBarrierSlow({:linear "tid"} tid:Tid) -ensures {:atomic} |{ A: assert tid != nil; goto B, C; - B: assume White(Color); Color := GRAY(); return true; - C: assume !White(Color); return true; }|; -{ - var colorLocal:int; - yield; - call AcquireLock(tid); - call colorLocal := GetColorLocked(tid); - if (White(colorLocal)) { call SetColorLocked(tid, GRAY()); } - call ReleaseLock(tid); - yield; -} - -procedure {:yields} {:layer 0,1} AcquireLock({:linear "tid"} tid: Tid); - ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; - -procedure {:yields} {:layer 0,1} ReleaseLock({:linear "tid"} tid: Tid); - ensures {:left} |{ A: assert tid != nil; assert lock == tid; lock := nil; return true; }|; - -procedure {:yields} {:layer 0,1} SetColorLocked({:linear "tid"} tid:Tid, newCol:int); - ensures {:atomic} |{A: assert tid != nil; assert lock == tid; Color := newCol; return true;}|; - -procedure {:yields} {:layer 0,1} GetColorLocked({:linear "tid"} tid:Tid) returns (col:int); - ensures {:both} |{A: assert tid != nil; assert lock == tid; col := Color; return true;}|; - -procedure {:yields} {:layer 0,2} GetColorNoLock() returns (col:int); - ensures {:atomic} |{A: col := Color; return true;}|; - - - -function {:builtin "MapConst"} MapConstBool(bool): [Tid]bool; -function {:builtin "MapOr"} MapOr([Tid]bool, [Tid]bool) : [Tid]bool; - -var {:layer 0} Color:int; -var {:layer 0} lock:Tid; - -function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool -{ - MapConstBool(false)[x := true] -} -function {:inline} {:linear "tid"} TidSetCollector(x: [Tid]bool) : [Tid]bool -{ - x -} +// RUN: %boogie -noinfer -typeEncoding:m -useArrayTheory "%s" > "%t" +// RUN: %diff "%s.expect" "%t" +type Tid; +const unique nil: Tid; + +function {:inline} UNALLOC():int { 0 } +function {:inline} WHITE():int { 1 } +function {:inline} GRAY():int { 2 } +function {:inline} BLACK():int { 3 } +function {:inline} Unalloc(i:int) returns(bool) { i <= 0 } +function {:inline} White(i:int) returns(bool) { i == 1 } +function {:inline} WhiteOrLighter(i:int) returns(bool) { i <= 1 } +function {:inline} Gray(i:int) returns(bool) { i == 2 } +function {:inline} Black(i:int) returns(bool) { i >= 3 } + +procedure {:yields} {:layer 2} YieldColorOnlyGetsDarker() +ensures {:layer 2} Color >= old(Color); +{ + yield; + assert {:layer 2} Color >= old(Color); +} + +procedure {:yields} {:layer 2,3} WriteBarrier({:linear "tid"} tid:Tid) +ensures {:atomic} |{ A: assert tid != nil; goto B, C; + B: assume White(Color); Color := GRAY(); return true; + C: assume !White(Color); return true;}|; +requires {:layer 2} Color >= WHITE(); +ensures {:layer 2} Color >= GRAY(); +{ + var colorLocal:int; + yield; + assert {:layer 2} Color >= WHITE(); + call colorLocal := GetColorNoLock(); + call YieldColorOnlyGetsDarker(); + if (WhiteOrLighter(colorLocal)) { call WriteBarrierSlow(tid); } + yield; + assert {:layer 2} Color >= GRAY(); +} + +procedure {:yields} {:layer 1,2} WriteBarrierSlow({:linear "tid"} tid:Tid) +ensures {:atomic} |{ A: assert tid != nil; goto B, C; + B: assume WhiteOrLighter(Color); Color := GRAY(); return true; + C: assume !WhiteOrLighter(Color); return true; }|; +{ + var colorLocal:int; + yield; + call AcquireLock(tid); + call colorLocal := GetColorLocked(tid); + if (WhiteOrLighter(colorLocal)) { call SetColorLocked(tid, GRAY()); } + call ReleaseLock(tid); + yield; +} + +procedure {:yields} {:layer 0,1} AcquireLock({:linear "tid"} tid: Tid); + ensures {:right} |{ A: assert tid != nil; assume lock == nil; lock := tid; return true; }|; + +procedure {:yields} {:layer 0,1} ReleaseLock({:linear "tid"} tid: Tid); + ensures {:left} |{ A: assert tid != nil; assert lock == tid; lock := nil; return true; }|; + +procedure {:yields} {:layer 0,1} SetColorLocked({:linear "tid"} tid:Tid, newCol:int); + ensures {:atomic} |{A: assert tid != nil; assert lock == tid; Color := newCol; return true;}|; + +procedure {:yields} {:layer 0,1} GetColorLocked({:linear "tid"} tid:Tid) returns (col:int); + ensures {:both} |{A: assert tid != nil; assert lock == tid; col := Color; return true;}|; + +procedure {:yields} {:layer 0,2} GetColorNoLock() returns (col:int); + ensures {:atomic} |{A: col := Color; return true;}|; + + + +function {:builtin "MapConst"} MapConstBool(bool): [Tid]bool; +function {:builtin "MapOr"} MapOr([Tid]bool, [Tid]bool) : [Tid]bool; + +var {:layer 0} Color:int; +var {:layer 0} lock:Tid; + +function {:inline} {:linear "tid"} TidCollector(x: Tid) : [Tid]bool +{ + MapConstBool(false)[x := true] +} +function {:inline} {:linear "tid"} TidSetCollector(x: [Tid]bool) : [Tid]bool +{ + x +} -- cgit v1.2.3 From 914f8b1b7cf0db8ba3fbb703d71e1ceb1d866120 Mon Sep 17 00:00:00 2001 From: qadeer Date: Thu, 25 Jun 2015 17:09:45 -0700 Subject: removed a stray Console.WriteLine that Ken had earlier checked in by mistake. --- Source/Provers/SMTLib/ProverInterface.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs index 0ff2efa7..8ded5f10 100644 --- a/Source/Provers/SMTLib/ProverInterface.cs +++ b/Source/Provers/SMTLib/ProverInterface.cs @@ -1172,7 +1172,6 @@ namespace Microsoft.Boogie.SMTLib usedLogNames.Add(curFilename); } - Console.WriteLine("opening log file {0}", curFilename); return new StreamWriter(curFilename, false); } -- cgit v1.2.3 From e11d65009d0b4ba1327f5f5dd6b26367330611f0 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Sun, 28 Jun 2015 00:46:18 +0100 Subject: Remove dead file. --- Source/Core/Graph.as | 352 --------------------------------------------------- 1 file changed, 352 deletions(-) delete mode 100644 Source/Core/Graph.as diff --git a/Source/Core/Graph.as b/Source/Core/Graph.as deleted file mode 100644 index 1466c341..00000000 --- a/Source/Core/Graph.as +++ /dev/null @@ -1,352 +0,0 @@ -using System.Collections; -namespace Graphing; - -type Node = object; -type Edge = ; - -class PreHeader { - Node myHeader; - PreHeader(Node h) { myHeader = h; } - - public override string ToString() { return "#" + myHeader.ToString(); } -} - -public class Graph { - private Set es; - private Set ns; - private Node source; - private bool reducible; - private Set headers; - private Map> backEdgeNodes; - private Map> naturalLoops; - private Map> dominatorMap; - private Map> immediateDominatorMap; - - public Graph(Set edges) - { - es = edges; - ns = Set{ x : in es } + Set{ y : in es }; - } - public Graph() - { es = Set{}; ns = Set{}; } - - public void AddSource(Node x) - { - ns += Set{x}; - source = x; - } - public void AddEdge(Node source, Node dest) - { - es += Set{}; - ns += Set{source, dest}; - } - - public Set Nodes { get { return ns; } } - public Set Edges { get { return es; } } - - public bool Edge(Node x, Node y) { return in es; } - Set predecessors(Node n) - { - Set result = Set{ x : x in Nodes, Edge(x,n) }; - return result; - } - public override string ToString() { return es.ToString(); } - - public IEnumerable TopologicalSort() - { - > = TopSort(this); - return res ? ns : null; - } - public void ComputeLoops() - { - , Map>, Map>> - = Reducible(this,this.source); - this.reducible = reducible; - this.headers = headers; - this.backEdgeNodes = backEdgeNodes; - this.naturalLoops = naturalLoops; - return; - } - public bool Reducible { get { return reducible; } } - public IEnumerable Headers { get { return headers; } } - public IEnumerable BackEdgeNodes(Node h) { return h in backEdgeNodes ? backEdgeNodes[h] : null; } - public IEnumerable NaturalLoops(Node header, Node backEdgeNode) - { Edge e = ; return e in naturalLoops ? naturalLoops[e] : null; } - public bool Acyclic { get { return Acyclic(this,this.source); } } - public Map> DominatorMap - { - get { - if (dominatorMap == null) dominatorMap = ComputeDominators(this, source); - return dominatorMap; - } - } - public Map> ImmediateDominatorMap - { - get { - if (immediateDominatorMap == null) - { - immediateDominatorMap = Map{}; - foreach(Node y in Nodes) - { - Set nodesThatYDominates = Set{ x : x in Nodes, x != y && (y in DominatorMap[x]) }; - Set immediateDominatees = Set{ x : x in nodesThatYDominates, - !(Exists{ v != y && v != x && (v in DominatorMap[x]) : v in nodesThatYDominates }) - }; - immediateDominatorMap[y] = immediateDominatees; - } - } - return immediateDominatorMap; - } - } - public Set ImmediatelyDominatedBy(Node n) { return ImmediateDominatorMap[n]; } - -} - -// From AsmL distribution example: TopologicalSort -> TopSort(Graph g) -{ - Seq S = Seq{}; - Set V = g.Nodes; - bool change = true; - while ( change ) - { - change = false; - Set X = V - ((Set) S); - if ( X != Set{} ) - { - Node temp = Choose{ v : v in X, !(Exists{ g.Edge(u,v) : u in X }) ifnone null }; - if ( temp == null ) - { - return {}>; - } - else if ( temp != Seq{} ) - { - S += Seq{temp}; - change = true; - } - } - } - return ; -} - -bool Acyclic(Graph g, Node source) -{ - > = TopSort(g); - return acyc; -} - -// -// [Dragon, pp. 670--671] -// returns map D s.t. d in D(n) iff d dom n -// -Map> ComputeDominators(Graph g, Node source) { - Set N = g.Nodes; - Set nonSourceNodes = N - Set{source}; - Map> D = Map{}; - D[source] = Set{ source }; - foreach (Node n in nonSourceNodes) - { - D[n] = N; - } - bool change = true; - while ( change ) - { - change = false; - foreach (Node n in nonSourceNodes) - { - Set> allPreds = Set{ D[p] : p in g.predecessors(n) }; - Set temp = Set{ n } + BigIntersect(allPreds); - if ( temp != D[n] ) - { - change = true; - D[n] = temp; - } - } - } - return D; -} - -// [Dragon, Fig. 10.15, p. 604. Algorithm for constructing the natural loop.] -Set NaturalLoop(Graph g, Edge backEdge) -{ - = backEdge; - Seq stack = Seq{}; - Set loop = Set{ d }; - if ( n != d ) // then n is not in loop - { - loop += Set{ n }; - stack = Seq{ n } + stack; // push n onto stack - } - while ( stack != Seq{} ) // not empty - { - Node m = Head(stack); - stack = Tail(stack); // pop stack - foreach (Node p in g.predecessors(m)) - { - if ( !(p in loop) ) - { - loop += Set{ p }; - stack = Seq{ p } + stack; // push p onto stack - } - } - } - return loop; -} - -// [Dragon, p. 606] -, Map>, Map>> - Reducible(Graph g, Node source) { - // first, compute the dom relation - Map> D = g.DominatorMap; - return Reducible(g,source,D); -} - -// [Dragon, p. 606] -, Map>, Map>> - Reducible(Graph g, Node source, Map> DomRelation) { - - Set edges = g.Edges; - Set backEdges = Set{}; - Set nonBackEdges = Set{}; - foreach (Edge e in edges) - { - = e; // so there is an edge from x to y - if ( y in DomRelation[x] ) // y dom x: which means y dominates x - { - backEdges += Set{ e }; - } - else - { - nonBackEdges += Set{ e }; - } - } - if ( !Acyclic(new Graph(nonBackEdges), source) ) - { - return {},Map>{},Map>{}>; - } - else - { - Set headers = Set{ d : in backEdges }; - Map> backEdgeNodes = Map{ h -> bs : h in headers, bs = Set{ b : in backEdges, x == h } }; - Map> naturalLoops = Map{ e -> NaturalLoop(g,e) : e in backEdges }; - - return ; - } -} - -// [Dragon, p. 606] -bool OldReducible(Graph g, Node source) { - // first, compute the dom relation - Map> D = ComputeDominators(g, source); - return OldReducible(g,source,D); -} - -// [Dragon, p. 606] -bool OldReducible(Graph g, Node source, Map> DomRelation) { - - Set edges = g.Edges; - Set backEdges = Set{}; - Set nonBackEdges = Set{}; - foreach (Edge e in edges) - { - = e; - if ( y in DomRelation[x] ) // y dom x - { - backEdges += Set{ e }; - } - else - { - nonBackEdges += Set{ e }; - } - } - WriteLine("backEdges: " + backEdges); - WriteLine("nonBackEdges: " + nonBackEdges); - if ( Acyclic(new Graph(nonBackEdges), source) ) - { - foreach(Edge e in backEdges) - { - Set naturalLoop = NaturalLoop(g,e); - WriteLine("Natural loop for back edge '" + e + "' is: " + naturalLoop); - } - Set headers = Set{ d : in backEdges }; - WriteLine("Loop headers = " + headers); - - edges -= backEdges; // this cuts all of the back edges - foreach (Node h in headers) - { - Set bs = Set{ : in backEdges, d == h }; - Set preds = Set{ p : in edges, y == h }; - Node preheader = new PreHeader(h); - edges += Set{ }; - foreach (Node p in preds) - { - edges -= Set{ }; - edges += Set{ }; - } - } - Graph newGraph = new Graph(edges); - WriteLine("transformed graph = " + newGraph); - return true; - } - else - { - return false; - } -} - -void Main() -{ - Graph g; - Map> D; -/* - g = new Graph(Set{ <1,2>, <1,3>, <2,3> }); - g.AddSource(1); - Map> doms = ComputeDominators(g,1); - WriteLine(doms); -*/ - g = new Graph(Set{ - <1,2>, <1,3>, - <2,3>, - <3,4>, - <4,3>, <4,5>, <4,6>, - <5,7>, - <6,7>, - <7,4>, <7,8>, - <8,3>, <8,9>, <8,10>, - <9,1>, - <10,7> - }); - g.AddSource(1); - WriteLine("G = " + g); - D = ComputeDominators(g,1); - WriteLine("Dom relation: " + D); - WriteLine("G's Dominator Map = " + g.DominatorMap); - WriteLine("G's Immediate Dominator Map = " + g.ImmediateDominatorMap); - WriteLine("G is reducible: " + OldReducible(g,1,D)); - g.ComputeLoops(); - - WriteLine(""); - - g = new Graph(Set{ <1,2>, <1,3>, <2,3>, <3,2> }); - g.AddSource(1); - WriteLine("G = " + g); - D = ComputeDominators(g,1); - WriteLine("Dom relation: " + D); - WriteLine("G's Dominator Map = " + g.DominatorMap); - WriteLine("G's Immediate Dominator Map = " + g.ImmediateDominatorMap); - WriteLine("G is reducible: " + OldReducible(g,1,D)); - g.ComputeLoops(); - - WriteLine(""); - - g = new Graph(Set{ <1,2>, <2,3>, <2,4>, <3,2> }); - g.AddSource(1); - WriteLine("G = " + g); - WriteLine("G's Dominator Map = " + g.DominatorMap); - WriteLine("G's Immediate Dominator Map = " + g.ImmediateDominatorMap); -// D = ComputeDominators(g,1); -// WriteLine("Dom relation: " + D); -// WriteLine("G is reducible: " + OldReducible(g,1,D)); - g.ComputeLoops(); - -} \ No newline at end of file -- cgit v1.2.3 From 962f8d5252b3f5ec4d19e0cd2a430934bd55cc6d Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Sun, 28 Jun 2015 01:44:30 +0100 Subject: Normalise line endings using a .gitattributes file. Unfortunately this required that this commit globally modify most files. If you want to use git blame to see the real author of a line use the ``-w`` flag so that whitespace changes are ignored. --- .gitattributes | 41 + Build/updateVersionFile.xml | 38 +- Source/AIFramework/AIFramework.csproj | 406 +- Source/AIFramework/CommonFunctionSymbols.cs | 2464 +- Source/AIFramework/Expr.cs | 1280 +- Source/AIFramework/Functional.cs | 860 +- Source/AIFramework/Lattice.cs | 1918 +- Source/AIFramework/Logger.cs | 112 +- Source/AIFramework/MultiLattice.cs | 1294 +- Source/AIFramework/Mutable.cs | 274 +- Source/AIFramework/Polyhedra/LinearConstraint.cs | 1088 +- .../Polyhedra/LinearConstraintSystem.cs | 3510 +- .../AIFramework/Polyhedra/PolyhedraAbstraction.cs | 1524 +- Source/AIFramework/Polyhedra/SimplexTableau.cs | 1260 +- .../AIFramework/VariableMap/ConstantAbstraction.cs | 502 +- .../AIFramework/VariableMap/ConstantExpressions.cs | 1056 +- .../AIFramework/VariableMap/DynamicTypeLattice.cs | 1022 +- Source/AIFramework/VariableMap/Intervals.cs | 1742 +- Source/AIFramework/VariableMap/MicroLattice.cs | 208 +- Source/AIFramework/VariableMap/Nullness.cs | 520 +- .../AIFramework/VariableMap/VariableMapLattice.cs | 1708 +- Source/AIFramework/cce.cs | 384 +- Source/AbsInt/AbsInt.csproj | 590 +- Source/AbsInt/IntervalDomain.cs | 2360 +- Source/AbsInt/NativeLattice.cs | 670 +- Source/AbsInt/Traverse.cs | 338 +- Source/AbsInt/TrivialDomain.cs | 158 +- Source/AbsInt/cce.cs | 124 +- Source/BVD/App.config | 10 +- Source/BVD/BVD.csproj | 212 +- Source/BVD/Program.cs | 56 +- Source/BVD/Properties/AssemblyInfo.cs | 72 +- Source/Basetypes/Basetypes.csproj | 406 +- Source/Basetypes/BigDec.cs | 760 +- Source/Basetypes/BigNum.cs | 722 +- Source/Basetypes/Rational.cs | 496 +- Source/Basetypes/Set.cs | 570 +- Source/Basetypes/cce.cs | 384 +- Source/Boogie.sln | 1286 +- Source/BoogieDriver/BoogieDriver.cs | 212 +- Source/BoogieDriver/BoogieDriver.csproj | 646 +- Source/BoogieDriver/cce.cs | 210 +- .../CodeContractsExtender.csproj | 404 +- Source/CodeContractsExtender/cce.cs | 366 +- Source/Concurrency/App.config | 12 +- Source/Concurrency/Concurrency.csproj | 228 +- Source/Concurrency/LinearSets.cs | 2008 +- Source/Concurrency/Program.cs | 88 +- Source/Concurrency/Properties/AssemblyInfo.cs | 72 +- Source/Concurrency/SimulationRelation.cs | 394 +- Source/Core/Absy.cs | 8964 +- Source/Core/AbsyCmd.cs | 6964 +- Source/Core/AbsyExpr.cs | 6514 +- Source/Core/AbsyQuant.cs | 1860 +- Source/Core/AbsyType.cs | 7392 +- Source/Core/AlphaEquality.cs | 324 +- Source/Core/BoogiePL.atg | 3022 +- Source/Core/CommandLineOptions.cs | 4338 +- Source/Core/Core.csproj | 470 +- Source/Core/Duplicator.cs | 1658 +- Source/Core/Inline.cs | 1538 +- Source/Core/InterProceduralReachabilityGraph.cs | 612 +- Source/Core/LambdaHelper.cs | 518 +- Source/Core/LoopUnroll.cs | 572 +- Source/Core/Makefile | 40 +- Source/Core/OOLongUtil.cs | 420 +- Source/Core/Parser.cs | 4586 +- Source/Core/Readme.txt | 122 +- Source/Core/ResolutionContext.cs | 1258 +- Source/Core/Scanner.cs | 1640 +- Source/Core/StandardVisitor.cs | 2322 +- Source/Core/TypeAmbiguitySeeker.cs | 244 +- Source/Core/Util.cs | 1376 +- Source/Core/VCExp.cs | 476 +- Source/Core/VariableDependenceAnalyser.cs | 1292 +- Source/Core/Xml.cs | 630 +- Source/Core/cce.cs | 384 +- Source/Doomed/DoomCheck.cs | 814 +- Source/Doomed/DoomErrorHandler.cs | 170 +- Source/Doomed/Doomed.csproj | 378 +- Source/Doomed/DoomedLoopUnrolling.cs | 1298 +- Source/Doomed/DoomedStrategy.cs | 1054 +- Source/Doomed/HasseDiagram.cs | 846 +- Source/Doomed/VCDoomed.cs | 1652 +- Source/ExecutionEngine/ExecutionEngine.cs | 3520 +- Source/ExecutionEngine/ExecutionEngine.csproj | 386 +- Source/ExecutionEngine/Properties/AssemblyInfo.cs | 72 +- Source/ExecutionEngine/VerificationResultCache.cs | 1424 +- Source/Forro.sln | 40 +- Source/Forro/Ast.fs | 76 +- Source/Forro/BoogieAst.fs | 80 +- Source/Forro/BoogiePrinter.fs | 224 +- Source/Forro/Forro.fsproj | 164 +- Source/Forro/Lexer.fsl | 120 +- Source/Forro/Main.fs | 114 +- Source/Forro/Parser.fsy | 244 +- Source/Forro/Printer.fs | 214 +- Source/Forro/Resolver.fs | 246 +- Source/Forro/Translator.fs | 434 +- Source/Graph/Graph.cs | 2894 +- Source/Graph/Graph.csproj | 398 +- Source/Graph/cce.cs | 384 +- Source/Houdini/AbstractHoudini.cs | 9428 +- Source/Houdini/AnnotationDependenceAnalyser.cs | 1756 +- Source/Houdini/Checker.cs | 912 +- Source/Houdini/ConcurrentHoudini.cs | 208 +- Source/Houdini/Houdini.cs | 2660 +- Source/Houdini/Houdini.csproj | 306 +- Source/Houdini/StagedHoudini.cs | 854 +- Source/Model/Model.cs | 1412 +- Source/Model/Model.csproj | 218 +- Source/Model/ModelParser.cs | 4 +- Source/Model/Properties/AssemblyInfo.cs | 46 +- Source/ModelViewer/BCTProvider.cs | 294 +- Source/ModelViewer/BaseProvider.cs | 272 +- Source/ModelViewer/DafnyProvider.cs | 776 +- Source/ModelViewer/DataModel.cs | 594 +- Source/ModelViewer/Main.Designer.cs | 998 +- Source/ModelViewer/Main.cs | 1740 +- Source/ModelViewer/Main.resx | 4382 +- Source/ModelViewer/ModelViewer.csproj | 422 +- Source/ModelViewer/Namer.cs | 1160 +- Source/ModelViewer/Properties/AssemblyInfo.cs | 50 +- .../ModelViewer/Properties/Resources.Designer.cs | 126 +- Source/ModelViewer/Properties/Resources.resx | 232 +- Source/ModelViewer/Properties/Settings.Designer.cs | 52 +- Source/ModelViewer/Properties/Settings.settings | 14 +- Source/ModelViewer/SourceView.Designer.cs | 124 +- Source/ModelViewer/SourceView.cs | 104 +- Source/ModelViewer/SourceView.resx | 238 +- Source/ModelViewer/TreeSkeleton.cs | 410 +- Source/ModelViewer/VccProvider.cs | 3052 +- Source/ParserHelper/ParserHelper.cs | 486 +- Source/ParserHelper/ParserHelper.csproj | 284 +- Source/Predication/Predication.csproj | 348 +- Source/Predication/SmartBlockPredicator.cs | 1274 +- Source/Predication/UniformityAnalyser.cs | 1082 +- Source/Provers/SMTLib/CVC4.cs | 142 +- Source/Provers/SMTLib/Inspector.cs | 314 +- Source/Provers/SMTLib/ProverInterface.cs | 5176 +- Source/Provers/SMTLib/SExpr.cs | 526 +- Source/Provers/SMTLib/SMTLib.csproj | 474 +- Source/Provers/SMTLib/SMTLibLineariser.cs | 1702 +- Source/Provers/SMTLib/SMTLibNamer.cs | 294 +- Source/Provers/SMTLib/SMTLibProverOptions.cs | 316 +- Source/Provers/SMTLib/TypeDeclCollector.cs | 790 +- Source/Provers/SMTLib/Z3.cs | 774 +- Source/Provers/SMTLib/cce.cs | 384 +- Source/Provers/TPTP/ProverInterface.cs | 702 +- Source/Provers/TPTP/TPTP.csproj | 260 +- Source/Provers/TPTP/TPTPLineariser.cs | 1480 +- Source/Provers/TPTP/TypeDeclCollector.cs | 270 +- Source/Provers/Z3api/ContextLayer.cs | 1454 +- Source/Provers/Z3api/ProverLayer.cs | 706 +- Source/Provers/Z3api/SafeContext.cs | 30 +- Source/Provers/Z3api/StubContext.cs | 148 +- Source/Provers/Z3api/TypeAdapter.cs | 392 +- Source/Provers/Z3api/VCExprVisitor.cs | 1298 +- Source/Provers/Z3api/Z3api.csproj | 376 +- Source/Provers/Z3api/cce.cs | 384 +- .../UnitTests/BasetypesTests/BasetypesTests.csproj | 136 +- .../BasetypesTests/Properties/AssemblyInfo.cs | 72 +- Source/UnitTests/BasetypesTests/packages.config | 6 +- Source/UnitTests/CoreTests/CoreTests.csproj | 166 +- Source/UnitTests/CoreTests/Duplicator.cs | 8 +- .../UnitTests/CoreTests/Properties/AssemblyInfo.cs | 72 +- Source/UnitTests/CoreTests/packages.config | 6 +- .../UnitTests/TestUtil/Properties/AssemblyInfo.cs | 72 +- Source/UnitTests/TestUtil/TestUtil.csproj | 140 +- Source/UnitTests/TestUtil/packages.config | 6 +- Source/VCExpr/BigLiteralAbstracter.cs | 462 +- Source/VCExpr/Boogie2VCExpr.cs | 2418 +- Source/VCExpr/Clustering.cs | 1042 +- Source/VCExpr/LetBindingSorter.cs | 322 +- Source/VCExpr/NameClashResolver.cs | 392 +- Source/VCExpr/SimplifyLikeLineariser.cs | 2196 +- Source/VCExpr/TermFormulaFlattening.cs | 494 +- Source/VCExpr/TypeErasure.cs | 3238 +- Source/VCExpr/TypeErasureArguments.cs | 1506 +- Source/VCExpr/TypeErasurePremisses.cs | 2674 +- Source/VCExpr/VCExpr.csproj | 446 +- Source/VCExpr/VCExprAST.cs | 4260 +- Source/VCExpr/VCExprASTPrinter.cs | 720 +- Source/VCExpr/VCExprASTVisitors.cs | 3052 +- Source/VCExpr/cce.cs | 384 +- Source/VCGeneration/Check.cs | 1378 +- Source/VCGeneration/ConditionGeneration.cs | 4018 +- Source/VCGeneration/Context.cs | 512 +- Source/VCGeneration/ExprExtensions.cs | 706 +- Source/VCGeneration/FixedpointVC.cs | 4490 +- Source/VCGeneration/OrderingAxioms.cs | 676 +- Source/VCGeneration/RPFP.cs | 1218 +- Source/VCGeneration/StratifiedVC.cs | 5806 +- Source/VCGeneration/VC.cs | 7802 +- Source/VCGeneration/VCGeneration.csproj | 446 +- Source/VCGeneration/Wlp.cs | 510 +- Source/VCGeneration/cce.cs | 210 +- Source/version.cs | 8 +- Source/version.ssc | 24 +- Test/AbsHoudini/Answer | 978 +- Test/AbsHoudini/f1.bpl | 64 +- Test/AbsHoudini/fail1.bpl | 36 +- Test/AbsHoudini/houd1.bpl | 38 +- Test/AbsHoudini/houd10.bpl | 48 +- Test/AbsHoudini/houd11.bpl | 30 +- Test/AbsHoudini/houd12.bpl | 120 +- Test/AbsHoudini/houd2.bpl | 58 +- Test/AbsHoudini/houd3.bpl | 58 +- Test/AbsHoudini/houd4.bpl | 58 +- Test/AbsHoudini/houd5.bpl | 62 +- Test/AbsHoudini/houd6.bpl | 92 +- Test/AbsHoudini/houd7.bpl | 74 +- Test/AbsHoudini/houd8.bpl | 62 +- Test/AbsHoudini/imp1.bpl | 42 +- Test/AbsHoudini/int1.bpl | 52 +- Test/AbsHoudini/multi.bpl | 134 +- Test/AbsHoudini/pred1.bpl | 50 +- Test/AbsHoudini/pred2.bpl | 28 +- Test/AbsHoudini/pred3.bpl | 52 +- Test/AbsHoudini/pred4.bpl | 46 +- Test/AbsHoudini/pred5.bpl | 52 +- Test/AbsHoudini/quant1.bpl | 18 +- Test/AbsHoudini/quant2.bpl | 52 +- Test/AbsHoudini/quant3.bpl | 18 +- Test/AbsHoudini/quant4.bpl | 18 +- Test/AbsHoudini/quant5.bpl | 26 +- Test/AbsHoudini/runtest.bat | 56 +- Test/AbsHoudini/test1.bpl | 80 +- Test/AbsHoudini/test10.bpl | 104 +- Test/AbsHoudini/test2.bpl | 84 +- Test/AbsHoudini/test7.bpl | 42 +- Test/AbsHoudini/test8.bpl | 54 +- Test/AbsHoudini/test9.bpl | 184 +- Test/README.md | 348 +- Test/aitest0/Intervals.bpl | 668 +- Test/aitest0/constants.bpl | 142 +- Test/aitest1/Bound.bpl | 60 +- Test/aitest1/Linear0.bpl | 24 +- Test/aitest1/Linear1.bpl | 26 +- Test/aitest1/Linear2.bpl | 26 +- Test/aitest1/Linear3.bpl | 26 +- Test/aitest1/Linear4.bpl | 38 +- Test/aitest1/Linear5.bpl | 50 +- Test/aitest1/Linear6.bpl | 46 +- Test/aitest1/Linear7.bpl | 42 +- Test/aitest1/Linear8.bpl | 88 +- Test/aitest1/Linear9.bpl | 62 +- Test/aitest1/ineq.bpl | 166 +- Test/aitest9/TestIntervals.bpl | 144 +- Test/aitest9/VarMapFixpoint.bpl | 120 +- Test/bitvectors/arrays.bpl | 84 +- Test/bitvectors/bv0.bpl | 30 +- Test/bitvectors/bv1.bpl | 38 +- Test/bitvectors/bv10.bpl | 24 +- Test/bitvectors/bv2.bpl | 26 +- Test/bitvectors/bv3.bpl | 10 +- Test/bitvectors/bv4.bpl | 50 +- Test/bitvectors/bv5.bpl | 26 +- Test/bitvectors/bv6.bpl | 22 +- Test/bitvectors/bv7.bpl | 22 +- Test/bitvectors/bv8.bpl | 50 +- Test/bitvectors/bv9.bpl | 50 +- Test/civl/DeviceCache.bpl | 420 +- Test/civl/DeviceCache.bpl.expect | 4 +- Test/civl/FlanaganQadeer.bpl | 148 +- Test/civl/FlanaganQadeer.bpl.expect | 4 +- Test/civl/Program1.bpl | 66 +- Test/civl/Program1.bpl.expect | 4 +- Test/civl/Program2.bpl | 74 +- Test/civl/Program2.bpl.expect | 4 +- Test/civl/Program3.bpl | 72 +- Test/civl/Program3.bpl.expect | 4 +- Test/civl/Program4.bpl | 136 +- Test/civl/Program4.bpl.expect | 4 +- Test/civl/Program5.bpl.expect | 4 +- Test/civl/akash.bpl | 210 +- Test/civl/akash.bpl.expect | 4 +- Test/civl/bar.bpl | 114 +- Test/civl/chris.bpl | 56 +- Test/civl/chris.bpl.expect | 4 +- Test/civl/chris2.bpl | 68 +- Test/civl/chris2.bpl.expect | 36 +- Test/civl/civl-paper.bpl | 350 +- Test/civl/civl-paper.bpl.expect | 4 +- Test/civl/foo.bpl | 114 +- Test/civl/linear-set.bpl | 210 +- Test/civl/linear-set.bpl.expect | 4 +- Test/civl/linear-set2.bpl | 212 +- Test/civl/linear-set2.bpl.expect | 4 +- Test/civl/lock-introduced.bpl | 200 +- Test/civl/lock-introduced.bpl.expect | 4 +- Test/civl/lock.bpl | 114 +- Test/civl/lock.bpl.expect | 4 +- Test/civl/lock2.bpl | 126 +- Test/civl/lock2.bpl.expect | 4 +- Test/civl/multiset.bpl | 648 +- Test/civl/multiset.bpl.expect | 4 +- Test/civl/new1.bpl | 84 +- Test/civl/new1.bpl.expect | 4 +- Test/civl/one.bpl | 36 +- Test/civl/one.bpl.expect | 4 +- Test/civl/parallel1.bpl | 96 +- Test/civl/parallel2.bpl | 118 +- Test/civl/parallel2.bpl.expect | 4 +- Test/civl/parallel4.bpl | 90 +- Test/civl/parallel4.bpl.expect | 12 +- Test/civl/parallel5.bpl | 118 +- Test/civl/parallel5.bpl.expect | 4 +- Test/civl/perm.bpl | 96 +- Test/civl/perm.bpl.expect | 4 +- Test/civl/t1.bpl | 206 +- Test/civl/termination.bpl | 36 +- Test/civl/termination.bpl.expect | 4 +- Test/civl/termination2.bpl | 38 +- Test/civl/termination2.bpl.expect | 4 +- Test/civl/ticket.bpl | 294 +- Test/civl/ticket.bpl.expect | 4 +- Test/civl/treiber-stack.bpl | 398 +- Test/civl/treiber-stack.bpl.expect | 4 +- Test/civl/wsq.bpl | 1118 +- Test/civl/wsq.bpl.expect | 4 +- Test/codeexpr/CodeExpr0.bpl | 110 +- Test/codeexpr/CodeExpr1.bpl | 138 +- Test/codeexpr/CodeExpr2.bpl | 104 +- Test/codeexpr/codeExprBug.bpl | 30 +- Test/codeexpr/codeExprBug.bpl.expect | 4 +- Test/datatypes/ex.bpl | 26 +- Test/datatypes/t1.bpl | 50 +- Test/datatypes/t2.bpl | 50 +- Test/doomed/doomdebug.bpl | 88 +- Test/doomed/doomed.bpl | 174 +- Test/doomed/notdoomed.bpl | 116 +- Test/doomed/runtest.bat | 32 +- Test/doomed/smoke0.bpl | 158 +- Test/extractloops/detLoopExtract.bpl | 4 +- Test/extractloops/t1.bpl | 86 +- Test/extractloops/t2.bpl | 108 +- Test/extractloops/t3.bpl | 86 +- Test/forro/prog0.forro | 78 +- Test/generalizedarray/Maps.bpl | 120 +- Test/havoc0/KbdCreateClassObject.bpl | 10314 +- Test/havoc0/KeyboardClassFindMorePorts.bpl | 7564 +- Test/havoc0/KeyboardClassUnload.bpl | 6670 +- Test/havoc0/MouCreateClassObject.bpl | 9840 +- Test/havoc0/MouseClassFindMorePorts.bpl | 7678 +- Test/havoc0/MouseClassUnload.bpl | 6742 +- Test/houdini/deterministic.bpl | 54 +- Test/houdini/deterministic.bpl.expect | 6 +- Test/houdini/houd1.bpl | 42 +- Test/houdini/houd10.bpl | 50 +- Test/houdini/houd11.bpl | 30 +- Test/houdini/houd12.bpl | 118 +- Test/houdini/houd2.bpl | 58 +- Test/houdini/houd3.bpl | 58 +- Test/houdini/houd4.bpl | 58 +- Test/houdini/houd5.bpl | 62 +- Test/houdini/houd6.bpl | 92 +- Test/houdini/houd7.bpl | 74 +- Test/houdini/houd8.bpl | 64 +- Test/houdini/houd9.bpl | 68 +- Test/houdini/mergedProgSingle_dac.bpl | 15232 +- Test/houdini/mergedProgSingle_dac.bpl.expect | 380 +- Test/houdini/mergedProgSingle_res_ex1.bpl | 1242 +- Test/houdini/mergedProgSingle_res_ex1.bpl.expect | 16 +- Test/houdini/mergedProgSingle_res_ex2.bpl | 1242 +- Test/houdini/mergedProgSingle_res_ex2.bpl.expect | 16 +- Test/houdini/test1.bpl | 76 +- Test/houdini/test10.bpl | 98 +- Test/houdini/test10.bpl.expect | 14 +- Test/houdini/test2.bpl | 80 +- Test/houdini/test7.bpl | 34 +- Test/houdini/test8.bpl | 46 +- Test/houdini/test9.bpl | 150 +- Test/houdini/testUnsatCore.bpl | 72 +- Test/houdini/testUnsatCore.bpl.expect | 14 +- Test/inline/Elevator.asml | 110 +- Test/inline/Elevator.bpl | 312 +- Test/inline/InliningAndLoops.bpl | 44 +- Test/inline/codeexpr.bpl | 124 +- Test/inline/expansion2.bpl | 38 +- Test/inline/expansion3.bpl | 26 +- Test/inline/expansion4.bpl | 22 +- Test/inline/fundef.bpl | 16 +- Test/inline/fundef2.bpl | 18 +- Test/inline/polyInline.bpl | 86 +- Test/inline/test0.bpl | 100 +- Test/inline/test1.bpl | 92 +- Test/inline/test2.bpl | 66 +- Test/inline/test3.bpl | 58 +- Test/inline/test4.bpl | 108 +- Test/inline/test5.bpl | 162 +- Test/inline/test6.bpl | 78 +- Test/linear/allocator.bpl | 24 +- Test/linear/async-bug.bpl | 72 +- Test/linear/async-bug.bpl.expect | 6 +- Test/linear/bug.bpl | 32 +- Test/linear/f1.bpl | 96 +- Test/linear/f2.bpl | 44 +- Test/linear/f3.bpl | 20 +- Test/linear/list.bpl | 100 +- Test/linear/typecheck.bpl | 230 +- Test/linear/typecheck.bpl.expect | 32 +- Test/livevars/NestedOneDimensionalMap.bpl | 62 +- Test/livevars/TwoDimensionalMap.bpl | 62 +- Test/livevars/bla1.bpl | 4204 +- Test/livevars/daytona_bug2_ioctl_example_1.bpl | 8024 +- Test/livevars/daytona_bug2_ioctl_example_2.bpl | 9720 +- Test/livevars/stack_overflow.bpl | 195938 +++++++++--------- Test/lock/Lock.bpl | 248 +- Test/lock/LockIncorrect.bpl | 106 +- Test/prover/EQ_v2.Eval__v4.Eval_out.bpl | 4514 +- Test/prover/z3mutl.bpl | 46 +- Test/smoke/smoke0.bpl | 110 +- Test/snapshots/Snapshots0.v0.bpl | 84 +- Test/snapshots/Snapshots0.v1.bpl | 84 +- Test/snapshots/Snapshots0.v2.bpl | 62 +- Test/snapshots/Snapshots1.v0.bpl | 28 +- Test/snapshots/Snapshots1.v1.bpl | 28 +- Test/snapshots/Snapshots1.v2.bpl | 30 +- Test/snapshots/Snapshots10.v0.bpl | 40 +- Test/snapshots/Snapshots10.v1.bpl | 42 +- Test/snapshots/Snapshots11.v0.bpl | 28 +- Test/snapshots/Snapshots11.v1.bpl | 30 +- Test/snapshots/Snapshots12.v0.bpl | 32 +- Test/snapshots/Snapshots12.v1.bpl | 32 +- Test/snapshots/Snapshots13.v0.bpl | 42 +- Test/snapshots/Snapshots13.v1.bpl | 32 +- Test/snapshots/Snapshots14.v0.bpl | 42 +- Test/snapshots/Snapshots14.v1.bpl | 42 +- Test/snapshots/Snapshots15.v0.bpl | 34 +- Test/snapshots/Snapshots15.v1.bpl | 34 +- Test/snapshots/Snapshots16.v0.bpl | 30 +- Test/snapshots/Snapshots16.v1.bpl | 30 +- Test/snapshots/Snapshots17.v0.bpl | 64 +- Test/snapshots/Snapshots17.v1.bpl | 64 +- Test/snapshots/Snapshots18.v0.bpl | 48 +- Test/snapshots/Snapshots18.v1.bpl | 48 +- Test/snapshots/Snapshots19.v0.bpl | 22 +- Test/snapshots/Snapshots19.v1.bpl | 22 +- Test/snapshots/Snapshots2.v0.bpl | 24 +- Test/snapshots/Snapshots2.v1.bpl | 24 +- Test/snapshots/Snapshots2.v2.bpl | 26 +- Test/snapshots/Snapshots2.v3.bpl | 26 +- Test/snapshots/Snapshots2.v4.bpl | 26 +- Test/snapshots/Snapshots2.v5.bpl | 28 +- Test/snapshots/Snapshots20.v0.bpl | 40 +- Test/snapshots/Snapshots20.v1.bpl | 40 +- Test/snapshots/Snapshots21.v0.bpl | 30 +- Test/snapshots/Snapshots21.v1.bpl | 30 +- Test/snapshots/Snapshots22.v0.bpl | 30 +- Test/snapshots/Snapshots22.v1.bpl | 30 +- Test/snapshots/Snapshots23.v0.bpl | 44 +- Test/snapshots/Snapshots23.v1.bpl | 46 +- Test/snapshots/Snapshots23.v2.bpl | 44 +- Test/snapshots/Snapshots24.v0.bpl | 50 +- Test/snapshots/Snapshots24.v1.bpl | 50 +- Test/snapshots/Snapshots25.v0.bpl | 28 +- Test/snapshots/Snapshots25.v1.bpl | 28 +- Test/snapshots/Snapshots26.v0.bpl | 28 +- Test/snapshots/Snapshots26.v1.bpl | 30 +- Test/snapshots/Snapshots27.v0.bpl | 28 +- Test/snapshots/Snapshots27.v1.bpl | 32 +- Test/snapshots/Snapshots28.v0.bpl | 30 +- Test/snapshots/Snapshots28.v1.bpl | 32 +- Test/snapshots/Snapshots29.v0.bpl | 30 +- Test/snapshots/Snapshots29.v1.bpl | 30 +- Test/snapshots/Snapshots3.v0.bpl | 36 +- Test/snapshots/Snapshots3.v1.bpl | 36 +- Test/snapshots/Snapshots30.v0.bpl | 26 +- Test/snapshots/Snapshots30.v1.bpl | 28 +- Test/snapshots/Snapshots31.v0.bpl | 30 +- Test/snapshots/Snapshots31.v1.bpl | 28 +- Test/snapshots/Snapshots32.v0.bpl | 30 +- Test/snapshots/Snapshots32.v1.bpl | 24 +- Test/snapshots/Snapshots33.v0.bpl | 30 +- Test/snapshots/Snapshots33.v1.bpl | 16 +- Test/snapshots/Snapshots34.v0.bpl | 14 +- Test/snapshots/Snapshots34.v1.bpl | 12 +- Test/snapshots/Snapshots35.v0.bpl | 14 +- Test/snapshots/Snapshots35.v1.bpl | 12 +- Test/snapshots/Snapshots36.v0.bpl | 28 +- Test/snapshots/Snapshots36.v1.bpl | 28 +- Test/snapshots/Snapshots37.v0.bpl | 18 +- Test/snapshots/Snapshots37.v1.bpl | 18 +- Test/snapshots/Snapshots4.v0.bpl | 72 +- Test/snapshots/Snapshots4.v1.bpl | 90 +- Test/snapshots/Snapshots5.v0.bpl | 22 +- Test/snapshots/Snapshots5.v1.bpl | 22 +- Test/snapshots/Snapshots6.v0.bpl | 34 +- Test/snapshots/Snapshots6.v1.bpl | 36 +- Test/snapshots/Snapshots7.v0.bpl | 38 +- Test/snapshots/Snapshots7.v1.bpl | 40 +- Test/snapshots/Snapshots8.v0.bpl | 30 +- Test/snapshots/Snapshots8.v1.bpl | 32 +- Test/snapshots/Snapshots9.v0.bpl | 34 +- Test/snapshots/Snapshots9.v1.bpl | 32 +- Test/snapshots/runtest.AI.snapshot | 4 +- Test/snapshots/runtest.AI.snapshot.expect | 18 +- Test/snapshots/runtest.snapshot | 4 +- Test/snapshots/runtest.snapshot.expect | 1336 +- Test/stratifiedinline/bar1.bpl | 56 +- Test/stratifiedinline/bar10.bpl | 86 +- Test/stratifiedinline/bar11.bpl | 66 +- Test/stratifiedinline/bar12.bpl | 20 +- Test/stratifiedinline/bar13.bpl | 72 +- Test/stratifiedinline/bar2.bpl | 50 +- Test/stratifiedinline/bar3.bpl | 82 +- Test/stratifiedinline/bar4.bpl | 78 +- Test/stratifiedinline/bar6.bpl | 76 +- Test/stratifiedinline/bar7.bpl | 90 +- Test/stratifiedinline/bar8.bpl | 88 +- Test/stratifiedinline/bar9.bpl | 94 +- Test/stratifiedinline/large.bpl | 33522 +-- Test/symdiff/foo.bpl | 38 +- Test/test0/Arrays0.bpl | 10 +- Test/test0/Arrays1.bpl | 44 +- Test/test0/AttributeParsing.bpl | 80 +- Test/test0/AttributeParsingErr.bpl | 50 +- Test/test0/AttributeResolution.bpl | 80 +- Test/test0/BadLabels0.bpl | 30 +- Test/test0/BadLabels1.bpl | 166 +- Test/test0/BadQuantifier.bpl | 10 +- Test/test0/EmptyCallArgs.bpl | 44 +- Test/test0/LargeLiterals0.bpl | 18 +- Test/test0/LineParse.bpl | 28 +- Test/test0/LineResolve.bpl | 90 +- Test/test0/MapsResolutionErrors.bpl | 60 +- Test/test0/ModifiedBag.bpl | 746 +- Test/test0/Orderings.bpl | 42 +- Test/test0/PrettyPrint.bpl | 134 +- Test/test0/Prog0.bpl | 106 +- Test/test0/Quoting.bpl | 36 +- Test/test0/SeparateVerification0.bpl | 54 +- Test/test0/SeparateVerification1.bpl | 42 +- Test/test0/Triggers0.bpl | 34 +- Test/test0/Triggers1.bpl | 258 +- Test/test0/Types0.bpl | 20 +- Test/test0/Types1.bpl | 18 +- Test/test0/WhereParsing.bpl | 72 +- Test/test0/WhereParsing0.bpl | 68 +- Test/test0/WhereParsing1.bpl | 34 +- Test/test0/WhereParsing2.bpl | 8 +- Test/test0/WhereResolution.bpl | 128 +- Test/test1/Arrays.bpl | 452 +- Test/test1/AssumptionVariables0.bpl | 114 +- Test/test1/AssumptionVariables1.bpl | 12 +- Test/test1/AssumptionVariables1.bpl.expect | 4 +- Test/test1/AttributeTyping.bpl | 74 +- Test/test1/EmptyCallArgs.bpl | 42 +- Test/test1/Family.bpl | 98 +- Test/test1/Frame0.bpl | 34 +- Test/test1/Frame1.bpl | 198 +- Test/test1/FunBody.bpl | 30 +- Test/test1/IfThenElse0.bpl | 4 +- Test/test1/IntReal.bpl | 100 +- Test/test1/Lambda.bpl | 4 +- Test/test1/LogicalExprs.bpl | 16 +- Test/test1/MapsTypeErrors.bpl | 258 +- Test/test1/Orderings.bpl | 20 +- Test/test1/UpdateExprTyping.bpl | 90 +- Test/test1/WhereTyping.bpl | 94 +- Test/test13/ErrorTraceTestLoopInvViolationBPL.bpl | 64 +- Test/test15/CaptureState.bpl | 58 +- Test/test15/IntInModel.bpl | 10 +- Test/test15/InterpretedFunctionTests.bpl | 38 +- Test/test15/ModelTest.bpl | 24 +- Test/test15/NullInModel.bpl | 14 +- Test/test16/LoopUnroll.bpl | 170 +- Test/test17/Answer | 16 +- Test/test17/contractinfer.bpl | 46 +- Test/test17/flpydisk.bpl | 4590 +- Test/test17/runtest.bat | 24 +- Test/test2/Arrays.bpl | 368 +- Test/test2/AssertVerifiedUnder0.bpl | 78 +- Test/test2/AssertVerifiedUnder0.bpl.expect | 22 +- Test/test2/AssumeEnsures.bpl | 142 +- Test/test2/AssumptionVariables0.bpl | 146 +- Test/test2/AssumptionVariables0.bpl.expect | 22 +- Test/test2/Axioms.bpl | 62 +- Test/test2/B.bpl | 176 +- Test/test2/Call.bpl | 124 +- Test/test2/CallVerifiedUnder0.bpl | 84 +- Test/test2/CallVerifiedUnder0.bpl.expect | 28 +- Test/test2/ContractEvaluationOrder.bpl | 72 +- Test/test2/CutBackEdge.bpl | 84 +- Test/test2/Ensures.bpl | 154 +- Test/test2/False.bpl | 36 +- Test/test2/FormulaTerm.bpl | 282 +- Test/test2/FormulaTerm2.bpl | 102 +- Test/test2/FreeCall.bpl | 168 +- Test/test2/IfThenElse1.bpl | 4 +- Test/test2/Implies.bpl | 76 +- Test/test2/InvariantVerifiedUnder0.bpl | 108 +- Test/test2/InvariantVerifiedUnder0.bpl.expect | 46 +- Test/test2/LambdaOldExpressions.bpl | 126 +- Test/test2/LambdaPoly.bpl | 4 +- Test/test2/LoopInvAssume.bpl | 44 +- Test/test2/NeverPattern.bpl | 140 +- Test/test2/NullaryMaps.bpl | 118 +- Test/test2/Old.bpl | 268 +- Test/test2/OldIllegal.bpl | 36 +- Test/test2/Passification.bpl | 342 +- Test/test2/Quantifiers.bpl | 312 +- Test/test2/SelectiveChecking.bpl | 4 +- Test/test2/Structured.bpl | 692 +- Test/test2/Timeouts0.bpl | 170 +- Test/test2/TypeEncodingM.bpl | 4 +- Test/test2/UpdateExpr.bpl | 166 +- Test/test2/Where.bpl | 330 +- Test/test2/sk_hack.bpl | 68 +- Test/test2/strings-no-where.bpl | 1994 +- Test/test2/strings-where.bpl | 1994 +- Test/test20/Coercions.bpl | 38 +- Test/test20/EmptySeq.bpl | 16 +- Test/test20/ParallelAssignment.bpl | 48 +- Test/test20/ParallelAssignment2.bpl | 24 +- Test/test20/PolyFuns0.bpl | 114 +- Test/test20/PolyFuns1.bpl | 122 +- Test/test20/PolyPolyPoly.bpl | 48 +- Test/test20/PolyPolyPoly2.bpl | 70 +- Test/test20/PolyProcs0.bpl | 70 +- Test/test20/ProcParamReordering.bpl | 32 +- Test/test20/Prog0.bpl | 74 +- Test/test20/Prog1.bpl | 56 +- Test/test20/Prog2.bpl | 36 +- Test/test20/TypeDecls0.bpl | 94 +- Test/test20/TypeDecls1.bpl | 50 +- Test/test20/TypeSynonyms0.bpl | 66 +- Test/test20/TypeSynonyms1.bpl | 98 +- Test/test20/TypeSynonyms2.bpl | 48 +- Test/test21/BooleanQuantification.bpl | 74 +- Test/test21/BooleanQuantification2.bpl | 38 +- Test/test21/Boxing.bpl | 52 +- Test/test21/Casts.bpl | 32 +- Test/test21/Coercions2.bpl | 58 +- Test/test21/Colors.bpl | 52 +- Test/test21/DisjointDomains.bpl | 72 +- Test/test21/DisjointDomains2.bpl | 140 +- Test/test21/EmptyList.bpl | 104 +- Test/test21/EmptySetBug.bpl | 72 +- Test/test21/Flattening.bpl | 36 +- Test/test21/FunAxioms.bpl | 90 +- Test/test21/FunAxioms2.bpl | 52 +- Test/test21/HeapAbstraction.bpl | 50 +- Test/test21/HeapAxiom.bpl | 66 +- Test/test21/InterestingExamples0.bpl | 26 +- Test/test21/InterestingExamples1.bpl | 66 +- Test/test21/InterestingExamples2.bpl | 40 +- Test/test21/InterestingExamples3.bpl | 66 +- Test/test21/InterestingExamples4.bpl | 96 +- Test/test21/InterestingExamples5.bpl | 42 +- Test/test21/Keywords.bpl | 28 +- Test/test21/LargeLiterals0.bpl | 50 +- Test/test21/LetSorting.bpl | 42 +- Test/test21/MapAxiomsConsistency.bpl | 206 +- Test/test21/MapOutputTypeParams.bpl | 76 +- Test/test21/Maps0.bpl | 124 +- Test/test21/Maps1.bpl | 84 +- Test/test21/Maps2.bpl | 62 +- Test/test21/NameClash.bpl | 26 +- Test/test21/Orderings.bpl | 50 +- Test/test21/Orderings2.bpl | 46 +- Test/test21/Orderings3.bpl | 86 +- Test/test21/Orderings4.bpl | 32 +- Test/test21/ParallelAssignment.bpl | 122 +- Test/test21/PolyList.bpl | 134 +- Test/test21/Real.bpl | 132 +- Test/test21/Triggers0.bpl | 98 +- Test/test21/Triggers1.bpl | 44 +- Test/test21/test3_AddMethod_conv.bpl | 3654 +- Test/test7/MultipleErrors.bpl | 76 +- Test/test7/NestedVC.bpl | 46 +- Test/test7/UnreachableBlocks.bpl | 84 +- Test/textbook/BQueue.bpl | 864 +- Test/textbook/Bubble.bpl | 164 +- Test/textbook/DivMod.bpl | 130 +- Test/textbook/DutchFlag.bpl | 142 +- Test/textbook/Find.bpl | 80 +- Test/textbook/McCarthy-91.bpl | 28 +- Test/textbook/TuringFactorial.bpl | 70 +- Test/z3api/Answer | 518 +- Test/z3api/Boog24.bpl | 34 +- Test/z3api/bar1.bpl | 52 +- Test/z3api/bar2.bpl | 48 +- Test/z3api/bar3.bpl | 82 +- Test/z3api/bar4.bpl | 76 +- Test/z3api/bar6.bpl | 72 +- Test/z3api/boog0.bpl | 98 +- Test/z3api/boog1.bpl | 34 +- Test/z3api/boog10.bpl | 48 +- Test/z3api/boog11.bpl | 36 +- Test/z3api/boog12.bpl | 44 +- Test/z3api/boog13.bpl | 56 +- Test/z3api/boog14.bpl | 22 +- Test/z3api/boog15.bpl | 20 +- Test/z3api/boog16.bpl | 22 +- Test/z3api/boog17.bpl | 52 +- Test/z3api/boog18.bpl | 30 +- Test/z3api/boog19.bpl | 460 +- Test/z3api/boog2.bpl | 46 +- Test/z3api/boog20.bpl | 36 +- Test/z3api/boog21.bpl | 38 +- Test/z3api/boog22.bpl | 20 +- Test/z3api/boog23.bpl | 824 +- Test/z3api/boog25.bpl | 568 +- Test/z3api/boog28.bpl | 34 +- Test/z3api/boog29.bpl | 40 +- Test/z3api/boog3.bpl | 14 +- Test/z3api/boog30.bpl | 28 +- Test/z3api/boog31.bpl | 30 +- Test/z3api/boog34.bpl | 20 +- Test/z3api/boog35.bpl | 32 +- Test/z3api/boog4.bpl | 86 +- Test/z3api/boog5.bpl | 86 +- Test/z3api/boog6.bpl | 48 +- Test/z3api/boog7.bpl | 42 +- Test/z3api/boog8.bpl | 52 +- Test/z3api/boog9.bpl | 46 +- Test/z3api/runtest.bat | 30 +- Util/BoogieBuildAndTest.cmd | 52 +- Util/Code Snippets/contractassertnonnull.snippet | 62 +- .../contractassertnonnullelem.snippet | 62 +- .../contractensuresnonnullelem.snippet | 60 +- Util/Code Snippets/contractensuresvalret.snippet | 60 +- .../contractensuresvalretNonNullElem.snippet | 60 +- Util/Code Snippets/contractinvnonnullelem.snippet | 62 +- .../contractrequiresnonnullelem.snippet | 62 +- Util/Emacs/boogie-mode.el | 240 +- Util/VS2010/Boogie/BoogieLanguageService.sln | 40 +- .../BoogieLanguageService.csproj | 356 +- .../Boogie/BoogieLanguageService/Configuration.cs | 48 +- .../BoogieLanguageService/GlobalSuppressions.cs | 22 +- .../VS2010/Boogie/BoogieLanguageService/Grammar.cs | 794 +- Util/VS2010/Boogie/BoogieLanguageService/Guids.cs | 24 +- .../Integration/AuthoringScope.cs | 130 +- .../Integration/Configuration.cs | 230 +- .../Integration/Declaration.cs | 58 +- .../Integration/Declarations.cs | 110 +- .../Integration/IASTResolver.cs | 24 +- .../Integration/IronyLanguageService.cs | 686 +- .../Integration/IronyViewFilter.cs | 84 +- .../Integration/LineScanner.cs | 116 +- .../BoogieLanguageService/Integration/Method.cs | 38 +- .../BoogieLanguageService/Integration/Methods.cs | 98 +- .../BoogieLanguageService/Integration/Package.cs | 258 +- .../BoogieLanguageService/Integration/Resolver.cs | 100 +- .../BoogieLanguageService/Integration/Source.cs | 80 +- .../IronyLanguageServicePackage.cs | 180 +- .../Properties/AssemblyInfo.cs | 72 +- .../BoogieLanguageService/Resources.Designer.cs | 126 +- .../Boogie/BoogieLanguageService/Resources.resx | 258 +- .../Boogie/BoogieLanguageService/VSPackage.resx | 256 +- .../source.extension.vsixmanifest | 54 +- Util/latex/boogie.sty | 242 +- 754 files changed, 301421 insertions(+), 301380 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d9e2956e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,41 @@ +# Autodetect text files and ensure that we normalise their +# line endings to lf internally. When checked out they may +# use different line endings. +* text=auto + +# Check out with crlf (Windows) line endings +*.sln text eol=crlf +*.csproj text eol=crlf +*.cs text diff=csharp eol=crlf +*.fs text eol=crlf +*.fsproj text eol=crlf +*.fsy text eol=crlf +*.fsl text eol=crlf +*.resx text eol=crlf +*.vsixmanifest text eol=crlf +*.atg text eol=crlf +version.ssc text eol=crlf +packages.config text eol=crlf +App.config text eol=crlf +Build/updateVersionFile.xml text eol=crlf +*.bat text eol=crlf +*.cmd text eol=crlf +*.snippet text eol=crlf + +# Check out with lf (UNIX) line endings +*.sh text eol=lf +*.py text eol=lf +Makefile text eol=lf +.gitignore text eol=lf +.gitattributes text eol=lf +*.el text eol=lf +*.sty text eol=lf +*.vim text eol=lf +lit.site.cfg text eol=lf +lit.local.cfg text eol=lf +*.expect text eol=lf +*.md text eol=lf + +# For the remaining files the line endings of checked out +# files is defined by the ``core.eol`` git config variable. +# By default this is the native line ending for the platform. diff --git a/Build/updateVersionFile.xml b/Build/updateVersionFile.xml index 6435133c..cb083c7a 100644 --- a/Build/updateVersionFile.xml +++ b/Build/updateVersionFile.xml @@ -1,19 +1,19 @@ - - - - - - - - - + + + + + + + + + diff --git a/Source/AIFramework/AIFramework.csproj b/Source/AIFramework/AIFramework.csproj index a809b8bf..a04074a6 100644 --- a/Source/AIFramework/AIFramework.csproj +++ b/Source/AIFramework/AIFramework.csproj @@ -1,204 +1,204 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {39B0658D-C955-41C5-9A43-48C97A1EF5FD} - Library - Properties - AIFramework - AIFramework - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for AIFramework.ruleset - true - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\AIFramework.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - - - - - - - version.cs - - - - - - - - - - - - - - - - - - - - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {39B0658D-C955-41C5-9A43-48C97A1EF5FD} + Library + Properties + AIFramework + AIFramework + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for AIFramework.ruleset + true + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\AIFramework.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + + + + + + + version.cs + + + + + + + + + + + + + + + + + + + + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/AIFramework/CommonFunctionSymbols.cs b/Source/AIFramework/CommonFunctionSymbols.cs index 6f7a9f93..6a287810 100644 --- a/Source/AIFramework/CommonFunctionSymbols.cs +++ b/Source/AIFramework/CommonFunctionSymbols.cs @@ -1,1232 +1,1232 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework -{ - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - //using Microsoft.SpecSharp.Collections; - using Microsoft.Basetypes; - - /// - /// A basic class for function symbols. - /// - public class FunctionSymbol : IFunctionSymbol - { - private readonly string/*!*/ display; - private readonly AIType/*!*/ typ; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(display != null); - Contract.Invariant(typ != null); - } - - - public FunctionSymbol(AIType/*!*/ typ) - : this("FunctionSymbol", typ) { - Contract.Requires(typ != null); - } - - internal FunctionSymbol(string/*!*/ display, AIType/*!*/ typ) { - Contract.Requires(typ != null); - Contract.Requires(display != null); - this.display = display; - this.typ = typ; - // base(); - } - - public AIType/*!*/ AIType { get { Contract.Ensures(Contract.Result() != null); return typ; } } - - [NoDefaultContract] - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return display; - } - - } - - /// - /// A class for integer constants. - /// - public class IntSymbol : FunctionSymbol - { - public readonly BigNum Value; - - /// - /// The intention is that this constructor be called only from the Int.Const method. - /// - internal IntSymbol(BigNum x) - : base(cce.NonNull(x.ToString()), Int.Type) { - this.Value = x; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - IntSymbol isym = other as IntSymbol; - return isym != null && isym.Value.Equals(this.Value); - } - - [Pure] - public override int GetHashCode() { - return Value.GetHashCode(); - } - } - - /// - /// A class for bitvector constants. - /// - public class BvSymbol : FunctionSymbol - { - public readonly BigNum Value; - public readonly int Bits; - - /// - /// The intention is that this constructor be called only from the Int.Const method. - /// - internal BvSymbol(BigNum x, int y) - : base(x + "bv" + y, Bv.Type) { - this.Value = x; - this.Bits = y; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - BvSymbol isym = other as BvSymbol; - return isym != null && isym.Value == this.Value && isym.Bits == this.Bits; - } - - [Pure] - public override int GetHashCode() { - unchecked { - return Value.GetHashCode() ^ Bits; - } - } - } - - public class DoubleSymbol : FunctionSymbol - { - public readonly double Value; - - /// - /// The intention is that this constructor be called only from the Double.Const method. - /// - internal DoubleSymbol(double x) - : base(cce.NonNull(x.ToString()), Double.Type) { - this.Value = x; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - DoubleSymbol dsym = other as DoubleSymbol; - return dsym != null && dsym.Value == this.Value; - } - - [Pure] - public override int GetHashCode() { - return Value.GetHashCode(); - } - } - - /// - /// Function symbol based on a string. Uses the string equality for determining equality - /// of symbol. - /// - public class NamedSymbol : FunctionSymbol - { - public string/*!*/ Value { [NoDefaultContract] get { Contract.Ensures(Contract.Result() != null); return cce.NonNull(this.ToString()); } } - - public NamedSymbol(string/*!*/ symbol, AIType/*!*/ typ) - : base(symbol, typ) { - Contract.Requires(typ != null); - Contract.Requires(symbol != null); - } - - [NoDefaultContract] - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - NamedSymbol nsym = other as NamedSymbol; - return nsym != null && this.Value.Equals(nsym.Value); - } - - [NoDefaultContract] - [Pure] - public override int GetHashCode() { - return Value.GetHashCode(); - } - } - - // - // In the following, the classes like Value and Prop serve two - // roles. The primary role is to be the base types for AIType. - // The only objects of these classes are the representative - // objects that denote an AIType, which are given by the - // "Type" property. Subtypes in the AIType language are - // encoded by subclassing. This yields some "higher-orderness" - // for checking subtyping in the AIType language, by using - // the Spec#/C# subclassing checks. - // - // The other role is simply as a module for collecting like function - // symbols. - // - - //-------------------------- Terms ---------------------------------- - - /// - /// A class with the equality symbol and the ValueType.Type. - /// - public class Value : AIType - { - private static readonly AIType/*!*/ valtype = new Value(); - public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return valtype; } } - - private static readonly FunctionType[]/*!*/ funtypeCache = new FunctionType[5]; - public static FunctionType/*!*/ FunctionType(int inParameterCount) { - Contract.Requires((0 <= inParameterCount)); - Contract.Ensures(Contract.Result() != null); - // Contract.Ensures(Contract.Result<>().Arity == inParameterCount); - FunctionType result; - if (inParameterCount < funtypeCache.Length) { - result = funtypeCache[inParameterCount]; - if (result != null) { - return result; - } - } - AIType[] signature = new AIType[1 + inParameterCount]; - for (int i = 0; i < signature.Length; i++) { - signature[i] = valtype; - } - result = new FunctionType(signature); - if (inParameterCount < funtypeCache.Length) { - funtypeCache[inParameterCount] = result; - } - return result; - } - - [Once] - private static AIType/*!*/ binreltype; - - private static AIType/*!*/ BinrelType { - get { - Contract.Ensures(Contract.Result() != null); - if (binreltype == null) { - binreltype = new FunctionType(Type, Type, Prop.Type); - } - return binreltype; - } - } - - [Once] - private static FunctionSymbol/*!*/ _eq; - public static FunctionSymbol/*!*/ Eq { - get { - Contract.Ensures(Contract.Result() != null); - if (_eq == null) { - _eq = new FunctionSymbol("=", BinrelType); - } - return _eq; - } - } - [Once] - private static FunctionSymbol/*!*/ _neq; - public static FunctionSymbol/*!*/ Neq { - get { - Contract.Ensures(Contract.Result() != null); - if (_neq == null) { - _neq = new FunctionSymbol("!=", BinrelType); - } - return _neq; - } - } - [Once] - private static FunctionSymbol/*!*/ _subtype; - public static FunctionSymbol/*!*/ Subtype { - get { - Contract.Ensures(Contract.Result() != null); - if (_subtype == null) { - _subtype = new FunctionSymbol("<:", BinrelType); - } - return _subtype; - } - } - - [Once] - private static AIType/*!*/ typeof_type; - private static AIType/*!*/ TypeofType { - get { - Contract.Ensures(Contract.Result() != null); - if (typeof_type == null) { - typeof_type = new FunctionType(Ref.Type, Type); - } - return typeof_type; - } - } - [Once] - private static FunctionSymbol/*!*/ _typeof; - public static FunctionSymbol/*!*/ Typeof { - get { - Contract.Ensures(Contract.Result() != null); - if (_typeof == null) { - _typeof = new FunctionSymbol("typeof", TypeofType); - } - return _typeof; - } - } - - /// - /// Value should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - protected Value() { } - - } - - public class Int : Value - { - private static readonly AIType/*!*/ inttype = new Int(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return inttype; } } - - private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); - private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); - private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); - - private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); - private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); - private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); - private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); - private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); - private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); - private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); - private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); - private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); - private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } - - public static IntSymbol/*!*/ Const(BigNum x) { - Contract.Ensures(Contract.Result() != null); - // We could cache things here, but for now we don't. - return new IntSymbol(x); - } - - /// - /// Int should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Int() { } - } - - public class Double : Value - { - private static readonly AIType/*!*/ doubletype = new Double(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return doubletype; } } - - public static DoubleSymbol/*!*/ Const(double x) { - Contract.Ensures(Contract.Result() != null); - // We could cache things here, but for now we don't. - return new DoubleSymbol(x); - } - - /// - /// Double should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Double() { } - } - - public class Bv : Value - { - private static readonly AIType/*!*/ bvtype = new Bv(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return bvtype; } } - - private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); - private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); - private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); - - private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); - private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); - private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); - private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); - private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); - private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); - private static readonly FunctionSymbol/*!*/ _concat = new FunctionSymbol("$concat", bininttype); - private static readonly FunctionSymbol/*!*/ _extract = new FunctionSymbol("$extract", unaryinttype); - private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); - private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); - private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); - private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Extract { get { Contract.Ensures(Contract.Result() != null); return _extract; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Concat { get { Contract.Ensures(Contract.Result() != null); return _concat; } } - - public static BvSymbol/*!*/ Const(BigNum x, int y) { - Contract.Ensures(Contract.Result() != null); - // We could cache things here, but for now we don't. - return new BvSymbol(x, y); - } - - /// - /// Int should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Bv() { } - } - - public class Ref : Value - { - private static readonly AIType/*!*/ reftype = new Ref(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } - - private static readonly FunctionSymbol/*!*/ _null = new FunctionSymbol("null", Type); - - public static FunctionSymbol/*!*/ Null { get { Contract.Ensures(Contract.Result() != null); return _null; } } - - /// - /// Ref should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Ref() { } - } - - public class HeapStructure : Value - { - private static readonly AIType/*!*/ reftype = new HeapStructure(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } - - - - /// - /// HeapStructure should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private HeapStructure() { } - } - - public class FieldName : Value - { - private static readonly AIType/*!*/ fieldnametype = new FieldName(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return fieldnametype; } } - - private static readonly FunctionSymbol/*!*/ _allocated = new FunctionSymbol("$allocated", FieldName.Type); - public static FunctionSymbol/*!*/ Allocated { get { Contract.Ensures(Contract.Result() != null); return _allocated; } } - - /// - /// Is this a boolean field that monotonically goes from false to true? - /// - public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol/*!*/ f) { - Contract.Requires(f != null); - return f.Equals(Allocated); - } - - /// - /// FieldName should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private FieldName() { } - } - - public class Heap : Value - { - private static readonly AIType/*!*/ heaptype = new Heap(); - public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return heaptype; } } - - // the types in the following, select1, select2, are hard-coded; - // these types may not always be appropriate - private static readonly FunctionSymbol/*!*/ _select1 = new FunctionSymbol("sel1", - // Heap x FieldName -> Prop - new FunctionType(Type, FieldName.Type, Prop.Type) - ); - public static FunctionSymbol/*!*/ Select1 { get { Contract.Ensures(Contract.Result() != null); return _select1; } } - - private static readonly FunctionSymbol/*!*/ _select2 = new FunctionSymbol("sel2", - // Heap x Ref x FieldName -> Value - new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type) - ); - public static FunctionSymbol/*!*/ Select2 { get { Contract.Ensures(Contract.Result() != null); return _select2; } } - - // the types in the following, store1, store2, are hard-coded; - // these types may not always be appropriate - private static readonly FunctionSymbol/*!*/ _update1 = new FunctionSymbol("upd1", - // Heap x FieldName x Value -> Heap - new FunctionType(Type, FieldName.Type, Value.Type, Type) - ); - public static FunctionSymbol/*!*/ Update1 { get { Contract.Ensures(Contract.Result() != null); return _update1; } } - - private static readonly FunctionSymbol/*!*/ _update2 = new FunctionSymbol("upd2", - // Heap x Ref x FieldName x Value -> Heap - new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type, Type) - ); - public static FunctionSymbol/*!*/ Update2 { get { Contract.Ensures(Contract.Result() != null); return _update2; } } - - private static readonly FunctionSymbol/*!*/ _unsupportedHeapOp = - new FunctionSymbol("UnsupportedHeapOp", - // Heap x FieldName -> Prop - new FunctionType(Type, FieldName.Type, Prop.Type) - ); - public static FunctionSymbol/*!*/ UnsupportedHeapOp { get { Contract.Ensures(Contract.Result() != null); return _unsupportedHeapOp; } } - - /// - /// Heap should not be instantiated from the outside, except perhaps in - /// subclasses. - /// - private Heap() { } - } - - // public class List : Value - // { - // private static IDictionary/**/! lists = new Hashtable(); - // public static AIType! Type(AIType! typeParameter) - // { - // if (lists.Contains(typeParameter)) - // return lists[typeParameter]; - // else - // { - // AIType! result = new List(typeParameter); - // lists[typeParameter] = result; - // return result; - // } - // } - // - // private static IDictionary/**/! nils = new Hashtable(); - // public static FunctionSymbol! Nil(AIType! typeParameter) - // { - // if (nils.Contains(typeParameter)) - // return nils[typeParameter]; - // else - // { - // FunctionSymbol! result = new FunctionSymbol(Type(typeParameter)); - // nils[typeParameter] = result; - // return result; - // } - // } - // - // private static IDictionary/**/! cons = new Hashtable(); - // public static FunctionSymbol! Cons(AIType! typeParameter) - // { - // if (cons.Contains(typeParameter)) - // return cons[typeParameter]; - // else - // { - // FunctionSymbol! result = new FunctionSymbol( - // new FunctionType(typeParameter, Type(typeParameter), Type(typeParameter)) - // ); - // cons[typeParameter] = result; - // return result; - // } - // } - // - // private AIType! typeParameter; - // public AIType(TypeParameter/*!*/ ){ - //Contract.Requires( != null); - //return typeParameter; } } - // - // /// - // /// List should not be instantiated from the outside. - // /// - // private List(AIType! typeParameter) - // { - // this.typeParameter = typeParameter; - // } - // } - // - // public class Pair : Value - // { - // private static IDictionary! pairs = new Hashtable(); - // public static AIType! Type(AIType! type1, AIType! type2) - // { - // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair - // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); - // - // if (pairs.Contains(typpair)) - // return pairs[typpair]; - // else - // { - // AIType! result = new Pair(type1, type2); - // pairs[typpair] = result; - // return result; - // } - // } - // - // private static IDictionary! constructs = new Hashtable(); - // public static FunctionSymbol! Pair(AIType! type1, AIType! type2) - // { - // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair - // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); - // - // if (constructs.Contains(typpair)) - // return constructs[typpair]; - // else - // { - // FunctionSymbol! result = new FunctionSymbol( - // new FunctionType(type1, type2, Type(type1, type2)) - // ); - // constructs[typpair] = result; - // return result; - // } - // } - // - // protected AIType! type1; - // protected AIType! type2; - // - // public AIType(Type1/*!*/ ){ - //Contract.Requires( != null); - // return type1; } } - // public AIType(Type2/*!*/ ){ - //Contract.Requires( != null); - // return type2; } } - // - // /// - // /// Pair should not be instantiated from the outside, except by subclasses. - // /// - // protected Pair(AIType! type1, AIType! type2) - // { - // this.type1 = type1; - // this.type2 = type2; - // } - // } - - //-------------------------- Propositions --------------------------- - - - /// - /// A class with global propositional symbols and the Prop.Type. - /// - public sealed class Prop : AIType - { - private static readonly AIType/*!*/ proptype = new Prop(); - - public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return proptype; } } - - private static readonly AIType/*!*/ unaryproptype = new FunctionType(Type, Type); - private static readonly AIType/*!*/ binproptype = new FunctionType(Type, Type, Type); - private static readonly AIType/*!*/ quantifiertype = - new FunctionType(new FunctionType(Value.Type, Type), Type); - - private static readonly FunctionSymbol/*!*/ _false = new FunctionSymbol("false", Type); - private static readonly FunctionSymbol/*!*/ _true = new FunctionSymbol("true", Type); - private static readonly FunctionSymbol/*!*/ _not = new FunctionSymbol("!", unaryproptype); - private static readonly FunctionSymbol/*!*/ _and = new FunctionSymbol("/\\", binproptype); - private static readonly FunctionSymbol/*!*/ _or = new FunctionSymbol("\\/", binproptype); - private static readonly FunctionSymbol/*!*/ _implies = new FunctionSymbol("==>", binproptype); - private static readonly FunctionSymbol/*!*/ _exists = new FunctionSymbol("Exists", quantifiertype); - private static readonly FunctionSymbol/*!*/ _forall = new FunctionSymbol("Forall", quantifiertype); - private static readonly FunctionSymbol/*!*/ _lambda = new FunctionSymbol("Lambda", quantifiertype); - - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ False { get { Contract.Ensures(Contract.Result() != null); return _false; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ True { get { Contract.Ensures(Contract.Result() != null); return _true; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Not { get { Contract.Ensures(Contract.Result() != null); return _not; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ And { [Pure] get { Contract.Ensures(Contract.Result() != null); return _and; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Or { get { Contract.Ensures(Contract.Result() != null); return _or; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Implies { get { Contract.Ensures(Contract.Result() != null); return _implies; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Exists { get { Contract.Ensures(Contract.Result() != null); return _exists; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Forall { get { Contract.Ensures(Contract.Result() != null); return _forall; } } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public static FunctionSymbol/*!*/ Lambda { get { Contract.Ensures(Contract.Result() != null); return _lambda; } } - - - /// - /// Prop should not be instantiated from the outside. - /// - private Prop() { } - - - - // - // Utility Methods - // - - public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IFunApp fun0 = e0 as IFunApp; - if (fun0 != null) { - if (fun0.FunctionSymbol.Equals(Prop.True)) { - return e1; - } else if (fun0.FunctionSymbol.Equals(Prop.False)) { - return e0; - } - } - - IFunApp fun1 = e1 as IFunApp; - if (fun1 != null) { - if (fun1.FunctionSymbol.Equals(Prop.True)) { - return e0; - } else if (fun1.FunctionSymbol.Equals(Prop.False)) { - return e1; - } - } - - return factory.And(e0, e1); - } - - public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { - Contract.Requires(exprs != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr/*!*/ result = factory.True; - Contract.Assert(result != null); - foreach (IExpr/*!*/ conjunct in exprs) { - Contract.Assert(conjunct != null); - result = SimplifiedAnd(factory, result, conjunct); - } - return result; - } - - public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IFunApp fun0 = e0 as IFunApp; - if (fun0 != null) { - if (fun0.FunctionSymbol.Equals(Prop.False)) { - return e1; - } else if (fun0.FunctionSymbol.Equals(Prop.True)) { - return e0; - } - } - - IFunApp fun1 = e1 as IFunApp; - if (fun1 != null) { - if (fun1.FunctionSymbol.Equals(Prop.False)) { - return e0; - } else if (fun1.FunctionSymbol.Equals(Prop.True)) { - return e1; - } - } - - return factory.Or(e0, e1); - } - - public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { - Contract.Requires(exprs != null); - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr/*!*/ result = factory.False; - Contract.Assert(result != null); - foreach (IExpr/*!*/ disj in exprs) { - Contract.Assert(disj != null); - result = SimplifiedOr(factory, result, disj); - } - return result; - } - - - - /// - /// Break top-level conjuncts into a list of sub-expressions. - /// - /// The expression to examine. - /// A list of conjuncts. - internal static IList/**//*!*/ BreakConjuncts(IExpr/*!*/ e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { - var sub = Contract.Result()[i]; - return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.And); - })); - return BreakJuncts(e, Prop.And); - } - - /// - /// Break top-level disjuncts into a list of sub-expressions. - /// - /// The expression to examine. - /// A list of conjuncts. - internal static IList/**//*!*/ BreakDisjuncts(IExpr/*!*/ e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { - var sub = Contract.Result()[i]; - return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.Or); - })); - return BreakJuncts(e, Prop.Or); - } - - private static IList/**//*!*/ BreakJuncts(IExpr/*!*/ e, IFunctionSymbol/*!*/ sym) { - Contract.Requires(sym != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { - var sub = Contract.Result()[i]; - return (sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(sym); - })); - ArrayList/**//*!*/ result = new ArrayList(); - - IFunApp f = e as IFunApp; - if (f != null) { - // If it is a sym, go down into sub-expressions. - if (f.FunctionSymbol.Equals(sym)) { - foreach (IExpr/*!*/ arg in f.Arguments) { - Contract.Assert(arg != null); - result.AddRange(BreakJuncts(arg, sym)); - } - } - // Otherwise, stop. - else { - result.Add(e); - } - } else { - result.Add(e); - } - - return result; - } - } - - /// - /// A callback to produce a function body given the bound variable. - /// - /// The bound variable to use. - /// The function body. - public delegate IExpr/*!*/ FunctionBody(IVariable/*!*/ var); - - /// - /// An interface for constructing propositional expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(IPropExprFactoryContracts))] - public interface IPropExprFactory - { - IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } - IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } - - IFunApp/*!*/ Not(IExpr/*!*/ p) /*ensures result.FunctionSymbol.Equals(Prop.Not);*/; - - IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; - IFunApp/*!*/ Or(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Or);*/; - - IFunApp/*!*/ Implies(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Implies);*/; - } - [ContractClassFor(typeof(IPropExprFactory))] - public abstract class IPropExprFactoryContracts : IPropExprFactory - { - #region IPropExprFactory Members - IFunApp IPropExprFactory.Implies(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IPropExprFactory.False { - - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp IPropExprFactory.True { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp IPropExprFactory.Not(IExpr p) { - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IPropExprFactory.And(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IPropExprFactory.Or(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - - - #endregion - } - - /// - /// An interface for constructing value expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(IValueExprFactoryContracts))] - public interface IValueExprFactory - { - IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; - IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; - } - [ContractClassFor(typeof(IValueExprFactory))] - public abstract class IValueExprFactoryContracts : IValueExprFactory - { - #region IValueExprFactory Members - - IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for constructing value expressions having to with null. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(INullnessFactoryContracts))] - public interface INullnessFactory - { - IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; - IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; - IFunApp/*!*/ Null { get; /*ensures result.FunctionSymbol.Equals(Ref.Null);*/ } - } - [ContractClassFor(typeof(INullnessFactory))] - public abstract class INullnessFactoryContracts : INullnessFactory - { - #region INullnessFactory Members - - IFunApp INullnessFactory.Eq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp INullnessFactory.Neq(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp INullnessFactory.Null { - get { - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - } - - #endregion - } - - /// - /// An interface for constructing integer expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(IIntExprFactoryContracts))] - public interface IIntExprFactory : IValueExprFactory - { - IFunApp/*!*/ Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/; - } - [ContractClassFor(typeof(IIntExprFactory))] - public abstract class IIntExprFactoryContracts : IIntExprFactory - { - - #region IIntExprFactory Members - - IFunApp IIntExprFactory.Const(BigNum i) { - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - - #region IValueExprFactory Members - - IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for constructing linear integer expressions. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(ILinearExprFactoryContracts))] - public interface ILinearExprFactory : IIntExprFactory - { - IFunApp/*!*/ AtMost(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.AtMost);*/; - IFunApp/*!*/ Add(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Add);*/; - /// - /// If "var" is null, returns an expression representing r. - /// Otherwise, returns an expression representing r*var. - /// - IExpr/*!*/ Term(Microsoft.Basetypes.Rational r, IVariable var); - - IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } - IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } - IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; - } - [ContractClassFor(typeof(ILinearExprFactory))] - public abstract class ILinearExprFactoryContracts : ILinearExprFactory - { - - #region ILinearExprFactory Members - - IFunApp ILinearExprFactory.AtMost(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ILinearExprFactory.Add(IExpr e0, IExpr e1) { - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IExpr ILinearExprFactory.Term(Rational r, IVariable var) { - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ILinearExprFactory.False { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp ILinearExprFactory.True { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - IFunApp ILinearExprFactory.And(IExpr p, IExpr q) { - Contract.Requires(p != null); - Contract.Requires(q != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - - #region IIntExprFactory Members - - IFunApp IIntExprFactory.Const(BigNum i) { - throw new System.NotImplementedException(); - } - - #endregion - - #region IValueExprFactory Members - - IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { - throw new System.NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for constructing type expressions and performing some type operations. - /// The types are assumed to be arranged in a rooted tree. - /// - /// This interface should be implemented by the client. An implementation of - /// of this class should generally be used as a singleton object. - /// - /// - [ContractClass(typeof(ITypeExprFactoryContracts))] - public interface ITypeExprFactory - { - /// - /// Returns an expression denoting the top of the type hierarchy. - /// - IExpr/*!*/ RootType { get; } - - /// - /// Returns true iff "t" denotes a type constant. - /// - [Pure] - bool IsTypeConstant(IExpr/*!*/ t); - - /// - /// Returns true iff t0 and t1 are types such that t0 and t1 are equal. - /// - [Pure] - bool IsTypeEqual(IExpr/*!*/ t0, IExpr/*!*/ t1); - - /// - /// Returns true iff t0 and t1 are types such that t0 is a subtype of t1. - /// - [Pure] - bool IsSubType(IExpr/*!*/ t0, IExpr/*!*/ t1); - - /// - /// Returns the most derived supertype of both "t0" and "t1". A precondition is - /// that "t0" and "t1" both represent types. - /// - IExpr/*!*/ JoinTypes(IExpr/*!*/ t0, IExpr/*!*/ t1); - - IFunApp/*!*/ IsExactlyA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Eq);*/; - IFunApp/*!*/ IsA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Subtype);*/; - } - [ContractClassFor(typeof(ITypeExprFactory))] - public abstract class ITypeExprFactoryContracts : ITypeExprFactory - { - - #region ITypeExprFactory Members - - IExpr ITypeExprFactory.RootType { - get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } - } - - bool ITypeExprFactory.IsTypeConstant(IExpr t) { - Contract.Requires(t != null); - throw new System.NotImplementedException(); - } - - bool ITypeExprFactory.IsTypeEqual(IExpr t0, IExpr t1) { - Contract.Requires(t0 != null); - Contract.Requires(t1 != null); - throw new System.NotImplementedException(); - } - - bool ITypeExprFactory.IsSubType(IExpr t0, IExpr t1) { - Contract.Requires(t0 != null); - Contract.Requires(t1 != null); - throw new System.NotImplementedException(); - } - - IExpr ITypeExprFactory.JoinTypes(IExpr t0, IExpr t1) { - Contract.Requires(t0 != null); - Contract.Requires(t1 != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ITypeExprFactory.IsExactlyA(IExpr e, IExpr type) { - Contract.Requires(e != null); - Contract.Requires(type != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - IFunApp ITypeExprFactory.IsA(IExpr e, IExpr type) { - Contract.Requires(e != null); - Contract.Requires(type != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - - #endregion - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + //using Microsoft.SpecSharp.Collections; + using Microsoft.Basetypes; + + /// + /// A basic class for function symbols. + /// + public class FunctionSymbol : IFunctionSymbol + { + private readonly string/*!*/ display; + private readonly AIType/*!*/ typ; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(display != null); + Contract.Invariant(typ != null); + } + + + public FunctionSymbol(AIType/*!*/ typ) + : this("FunctionSymbol", typ) { + Contract.Requires(typ != null); + } + + internal FunctionSymbol(string/*!*/ display, AIType/*!*/ typ) { + Contract.Requires(typ != null); + Contract.Requires(display != null); + this.display = display; + this.typ = typ; + // base(); + } + + public AIType/*!*/ AIType { get { Contract.Ensures(Contract.Result() != null); return typ; } } + + [NoDefaultContract] + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return display; + } + + } + + /// + /// A class for integer constants. + /// + public class IntSymbol : FunctionSymbol + { + public readonly BigNum Value; + + /// + /// The intention is that this constructor be called only from the Int.Const method. + /// + internal IntSymbol(BigNum x) + : base(cce.NonNull(x.ToString()), Int.Type) { + this.Value = x; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + IntSymbol isym = other as IntSymbol; + return isym != null && isym.Value.Equals(this.Value); + } + + [Pure] + public override int GetHashCode() { + return Value.GetHashCode(); + } + } + + /// + /// A class for bitvector constants. + /// + public class BvSymbol : FunctionSymbol + { + public readonly BigNum Value; + public readonly int Bits; + + /// + /// The intention is that this constructor be called only from the Int.Const method. + /// + internal BvSymbol(BigNum x, int y) + : base(x + "bv" + y, Bv.Type) { + this.Value = x; + this.Bits = y; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + BvSymbol isym = other as BvSymbol; + return isym != null && isym.Value == this.Value && isym.Bits == this.Bits; + } + + [Pure] + public override int GetHashCode() { + unchecked { + return Value.GetHashCode() ^ Bits; + } + } + } + + public class DoubleSymbol : FunctionSymbol + { + public readonly double Value; + + /// + /// The intention is that this constructor be called only from the Double.Const method. + /// + internal DoubleSymbol(double x) + : base(cce.NonNull(x.ToString()), Double.Type) { + this.Value = x; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + DoubleSymbol dsym = other as DoubleSymbol; + return dsym != null && dsym.Value == this.Value; + } + + [Pure] + public override int GetHashCode() { + return Value.GetHashCode(); + } + } + + /// + /// Function symbol based on a string. Uses the string equality for determining equality + /// of symbol. + /// + public class NamedSymbol : FunctionSymbol + { + public string/*!*/ Value { [NoDefaultContract] get { Contract.Ensures(Contract.Result() != null); return cce.NonNull(this.ToString()); } } + + public NamedSymbol(string/*!*/ symbol, AIType/*!*/ typ) + : base(symbol, typ) { + Contract.Requires(typ != null); + Contract.Requires(symbol != null); + } + + [NoDefaultContract] + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + NamedSymbol nsym = other as NamedSymbol; + return nsym != null && this.Value.Equals(nsym.Value); + } + + [NoDefaultContract] + [Pure] + public override int GetHashCode() { + return Value.GetHashCode(); + } + } + + // + // In the following, the classes like Value and Prop serve two + // roles. The primary role is to be the base types for AIType. + // The only objects of these classes are the representative + // objects that denote an AIType, which are given by the + // "Type" property. Subtypes in the AIType language are + // encoded by subclassing. This yields some "higher-orderness" + // for checking subtyping in the AIType language, by using + // the Spec#/C# subclassing checks. + // + // The other role is simply as a module for collecting like function + // symbols. + // + + //-------------------------- Terms ---------------------------------- + + /// + /// A class with the equality symbol and the ValueType.Type. + /// + public class Value : AIType + { + private static readonly AIType/*!*/ valtype = new Value(); + public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return valtype; } } + + private static readonly FunctionType[]/*!*/ funtypeCache = new FunctionType[5]; + public static FunctionType/*!*/ FunctionType(int inParameterCount) { + Contract.Requires((0 <= inParameterCount)); + Contract.Ensures(Contract.Result() != null); + // Contract.Ensures(Contract.Result<>().Arity == inParameterCount); + FunctionType result; + if (inParameterCount < funtypeCache.Length) { + result = funtypeCache[inParameterCount]; + if (result != null) { + return result; + } + } + AIType[] signature = new AIType[1 + inParameterCount]; + for (int i = 0; i < signature.Length; i++) { + signature[i] = valtype; + } + result = new FunctionType(signature); + if (inParameterCount < funtypeCache.Length) { + funtypeCache[inParameterCount] = result; + } + return result; + } + + [Once] + private static AIType/*!*/ binreltype; + + private static AIType/*!*/ BinrelType { + get { + Contract.Ensures(Contract.Result() != null); + if (binreltype == null) { + binreltype = new FunctionType(Type, Type, Prop.Type); + } + return binreltype; + } + } + + [Once] + private static FunctionSymbol/*!*/ _eq; + public static FunctionSymbol/*!*/ Eq { + get { + Contract.Ensures(Contract.Result() != null); + if (_eq == null) { + _eq = new FunctionSymbol("=", BinrelType); + } + return _eq; + } + } + [Once] + private static FunctionSymbol/*!*/ _neq; + public static FunctionSymbol/*!*/ Neq { + get { + Contract.Ensures(Contract.Result() != null); + if (_neq == null) { + _neq = new FunctionSymbol("!=", BinrelType); + } + return _neq; + } + } + [Once] + private static FunctionSymbol/*!*/ _subtype; + public static FunctionSymbol/*!*/ Subtype { + get { + Contract.Ensures(Contract.Result() != null); + if (_subtype == null) { + _subtype = new FunctionSymbol("<:", BinrelType); + } + return _subtype; + } + } + + [Once] + private static AIType/*!*/ typeof_type; + private static AIType/*!*/ TypeofType { + get { + Contract.Ensures(Contract.Result() != null); + if (typeof_type == null) { + typeof_type = new FunctionType(Ref.Type, Type); + } + return typeof_type; + } + } + [Once] + private static FunctionSymbol/*!*/ _typeof; + public static FunctionSymbol/*!*/ Typeof { + get { + Contract.Ensures(Contract.Result() != null); + if (_typeof == null) { + _typeof = new FunctionSymbol("typeof", TypeofType); + } + return _typeof; + } + } + + /// + /// Value should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + protected Value() { } + + } + + public class Int : Value + { + private static readonly AIType/*!*/ inttype = new Int(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return inttype; } } + + private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); + private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); + private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); + + private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); + private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); + private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); + private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); + private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); + private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); + private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); + private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); + private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); + private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } + + public static IntSymbol/*!*/ Const(BigNum x) { + Contract.Ensures(Contract.Result() != null); + // We could cache things here, but for now we don't. + return new IntSymbol(x); + } + + /// + /// Int should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Int() { } + } + + public class Double : Value + { + private static readonly AIType/*!*/ doubletype = new Double(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return doubletype; } } + + public static DoubleSymbol/*!*/ Const(double x) { + Contract.Ensures(Contract.Result() != null); + // We could cache things here, but for now we don't. + return new DoubleSymbol(x); + } + + /// + /// Double should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Double() { } + } + + public class Bv : Value + { + private static readonly AIType/*!*/ bvtype = new Bv(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return bvtype; } } + + private static readonly AIType/*!*/ unaryinttype = new FunctionType(Type, Type); + private static readonly AIType/*!*/ bininttype = new FunctionType(Type, Type, Type); + private static readonly AIType/*!*/ relationtype = new FunctionType(Type, Type, Prop.Type); + + private static readonly FunctionSymbol/*!*/ _negate = new FunctionSymbol("~", unaryinttype); + private static readonly FunctionSymbol/*!*/ _add = new FunctionSymbol("+", bininttype); + private static readonly FunctionSymbol/*!*/ _sub = new FunctionSymbol("-", bininttype); + private static readonly FunctionSymbol/*!*/ _mul = new FunctionSymbol("*", bininttype); + private static readonly FunctionSymbol/*!*/ _div = new FunctionSymbol("/", bininttype); + private static readonly FunctionSymbol/*!*/ _mod = new FunctionSymbol("%", bininttype); + private static readonly FunctionSymbol/*!*/ _concat = new FunctionSymbol("$concat", bininttype); + private static readonly FunctionSymbol/*!*/ _extract = new FunctionSymbol("$extract", unaryinttype); + private static readonly FunctionSymbol/*!*/ _atmost = new FunctionSymbol("<=", relationtype); + private static readonly FunctionSymbol/*!*/ _less = new FunctionSymbol("<", relationtype); + private static readonly FunctionSymbol/*!*/ _greater = new FunctionSymbol(">", relationtype); + private static readonly FunctionSymbol/*!*/ _atleast = new FunctionSymbol(">=", relationtype); + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Negate { get { Contract.Ensures(Contract.Result() != null); return _negate; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result() != null); return _add; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result() != null); return _sub; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result() != null); return _mul; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result() != null); return _div; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result() != null); return _mod; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result() != null); return _atmost; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result() != null); return _less; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result() != null); return _greater; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result() != null); return _atleast; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Extract { get { Contract.Ensures(Contract.Result() != null); return _extract; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Concat { get { Contract.Ensures(Contract.Result() != null); return _concat; } } + + public static BvSymbol/*!*/ Const(BigNum x, int y) { + Contract.Ensures(Contract.Result() != null); + // We could cache things here, but for now we don't. + return new BvSymbol(x, y); + } + + /// + /// Int should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Bv() { } + } + + public class Ref : Value + { + private static readonly AIType/*!*/ reftype = new Ref(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } + + private static readonly FunctionSymbol/*!*/ _null = new FunctionSymbol("null", Type); + + public static FunctionSymbol/*!*/ Null { get { Contract.Ensures(Contract.Result() != null); return _null; } } + + /// + /// Ref should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Ref() { } + } + + public class HeapStructure : Value + { + private static readonly AIType/*!*/ reftype = new HeapStructure(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return reftype; } } + + + + /// + /// HeapStructure should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private HeapStructure() { } + } + + public class FieldName : Value + { + private static readonly AIType/*!*/ fieldnametype = new FieldName(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return fieldnametype; } } + + private static readonly FunctionSymbol/*!*/ _allocated = new FunctionSymbol("$allocated", FieldName.Type); + public static FunctionSymbol/*!*/ Allocated { get { Contract.Ensures(Contract.Result() != null); return _allocated; } } + + /// + /// Is this a boolean field that monotonically goes from false to true? + /// + public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol/*!*/ f) { + Contract.Requires(f != null); + return f.Equals(Allocated); + } + + /// + /// FieldName should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private FieldName() { } + } + + public class Heap : Value + { + private static readonly AIType/*!*/ heaptype = new Heap(); + public static new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return heaptype; } } + + // the types in the following, select1, select2, are hard-coded; + // these types may not always be appropriate + private static readonly FunctionSymbol/*!*/ _select1 = new FunctionSymbol("sel1", + // Heap x FieldName -> Prop + new FunctionType(Type, FieldName.Type, Prop.Type) + ); + public static FunctionSymbol/*!*/ Select1 { get { Contract.Ensures(Contract.Result() != null); return _select1; } } + + private static readonly FunctionSymbol/*!*/ _select2 = new FunctionSymbol("sel2", + // Heap x Ref x FieldName -> Value + new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type) + ); + public static FunctionSymbol/*!*/ Select2 { get { Contract.Ensures(Contract.Result() != null); return _select2; } } + + // the types in the following, store1, store2, are hard-coded; + // these types may not always be appropriate + private static readonly FunctionSymbol/*!*/ _update1 = new FunctionSymbol("upd1", + // Heap x FieldName x Value -> Heap + new FunctionType(Type, FieldName.Type, Value.Type, Type) + ); + public static FunctionSymbol/*!*/ Update1 { get { Contract.Ensures(Contract.Result() != null); return _update1; } } + + private static readonly FunctionSymbol/*!*/ _update2 = new FunctionSymbol("upd2", + // Heap x Ref x FieldName x Value -> Heap + new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type, Type) + ); + public static FunctionSymbol/*!*/ Update2 { get { Contract.Ensures(Contract.Result() != null); return _update2; } } + + private static readonly FunctionSymbol/*!*/ _unsupportedHeapOp = + new FunctionSymbol("UnsupportedHeapOp", + // Heap x FieldName -> Prop + new FunctionType(Type, FieldName.Type, Prop.Type) + ); + public static FunctionSymbol/*!*/ UnsupportedHeapOp { get { Contract.Ensures(Contract.Result() != null); return _unsupportedHeapOp; } } + + /// + /// Heap should not be instantiated from the outside, except perhaps in + /// subclasses. + /// + private Heap() { } + } + + // public class List : Value + // { + // private static IDictionary/**/! lists = new Hashtable(); + // public static AIType! Type(AIType! typeParameter) + // { + // if (lists.Contains(typeParameter)) + // return lists[typeParameter]; + // else + // { + // AIType! result = new List(typeParameter); + // lists[typeParameter] = result; + // return result; + // } + // } + // + // private static IDictionary/**/! nils = new Hashtable(); + // public static FunctionSymbol! Nil(AIType! typeParameter) + // { + // if (nils.Contains(typeParameter)) + // return nils[typeParameter]; + // else + // { + // FunctionSymbol! result = new FunctionSymbol(Type(typeParameter)); + // nils[typeParameter] = result; + // return result; + // } + // } + // + // private static IDictionary/**/! cons = new Hashtable(); + // public static FunctionSymbol! Cons(AIType! typeParameter) + // { + // if (cons.Contains(typeParameter)) + // return cons[typeParameter]; + // else + // { + // FunctionSymbol! result = new FunctionSymbol( + // new FunctionType(typeParameter, Type(typeParameter), Type(typeParameter)) + // ); + // cons[typeParameter] = result; + // return result; + // } + // } + // + // private AIType! typeParameter; + // public AIType(TypeParameter/*!*/ ){ + //Contract.Requires( != null); + //return typeParameter; } } + // + // /// + // /// List should not be instantiated from the outside. + // /// + // private List(AIType! typeParameter) + // { + // this.typeParameter = typeParameter; + // } + // } + // + // public class Pair : Value + // { + // private static IDictionary! pairs = new Hashtable(); + // public static AIType! Type(AIType! type1, AIType! type2) + // { + // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair + // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); + // + // if (pairs.Contains(typpair)) + // return pairs[typpair]; + // else + // { + // AIType! result = new Pair(type1, type2); + // pairs[typpair] = result; + // return result; + // } + // } + // + // private static IDictionary! constructs = new Hashtable(); + // public static FunctionSymbol! Pair(AIType! type1, AIType! type2) + // { + // Microsoft.AbstractInterpretationFramework.Collections.Pair typpair + // = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2); + // + // if (constructs.Contains(typpair)) + // return constructs[typpair]; + // else + // { + // FunctionSymbol! result = new FunctionSymbol( + // new FunctionType(type1, type2, Type(type1, type2)) + // ); + // constructs[typpair] = result; + // return result; + // } + // } + // + // protected AIType! type1; + // protected AIType! type2; + // + // public AIType(Type1/*!*/ ){ + //Contract.Requires( != null); + // return type1; } } + // public AIType(Type2/*!*/ ){ + //Contract.Requires( != null); + // return type2; } } + // + // /// + // /// Pair should not be instantiated from the outside, except by subclasses. + // /// + // protected Pair(AIType! type1, AIType! type2) + // { + // this.type1 = type1; + // this.type2 = type2; + // } + // } + + //-------------------------- Propositions --------------------------- + + + /// + /// A class with global propositional symbols and the Prop.Type. + /// + public sealed class Prop : AIType + { + private static readonly AIType/*!*/ proptype = new Prop(); + + public static AIType/*!*/ Type { get { Contract.Ensures(Contract.Result() != null); return proptype; } } + + private static readonly AIType/*!*/ unaryproptype = new FunctionType(Type, Type); + private static readonly AIType/*!*/ binproptype = new FunctionType(Type, Type, Type); + private static readonly AIType/*!*/ quantifiertype = + new FunctionType(new FunctionType(Value.Type, Type), Type); + + private static readonly FunctionSymbol/*!*/ _false = new FunctionSymbol("false", Type); + private static readonly FunctionSymbol/*!*/ _true = new FunctionSymbol("true", Type); + private static readonly FunctionSymbol/*!*/ _not = new FunctionSymbol("!", unaryproptype); + private static readonly FunctionSymbol/*!*/ _and = new FunctionSymbol("/\\", binproptype); + private static readonly FunctionSymbol/*!*/ _or = new FunctionSymbol("\\/", binproptype); + private static readonly FunctionSymbol/*!*/ _implies = new FunctionSymbol("==>", binproptype); + private static readonly FunctionSymbol/*!*/ _exists = new FunctionSymbol("Exists", quantifiertype); + private static readonly FunctionSymbol/*!*/ _forall = new FunctionSymbol("Forall", quantifiertype); + private static readonly FunctionSymbol/*!*/ _lambda = new FunctionSymbol("Lambda", quantifiertype); + + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ False { get { Contract.Ensures(Contract.Result() != null); return _false; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ True { get { Contract.Ensures(Contract.Result() != null); return _true; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Not { get { Contract.Ensures(Contract.Result() != null); return _not; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ And { [Pure] get { Contract.Ensures(Contract.Result() != null); return _and; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Or { get { Contract.Ensures(Contract.Result() != null); return _or; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Implies { get { Contract.Ensures(Contract.Result() != null); return _implies; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Exists { get { Contract.Ensures(Contract.Result() != null); return _exists; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Forall { get { Contract.Ensures(Contract.Result() != null); return _forall; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Lambda { get { Contract.Ensures(Contract.Result() != null); return _lambda; } } + + + /// + /// Prop should not be instantiated from the outside. + /// + private Prop() { } + + + + // + // Utility Methods + // + + public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IFunApp fun0 = e0 as IFunApp; + if (fun0 != null) { + if (fun0.FunctionSymbol.Equals(Prop.True)) { + return e1; + } else if (fun0.FunctionSymbol.Equals(Prop.False)) { + return e0; + } + } + + IFunApp fun1 = e1 as IFunApp; + if (fun1 != null) { + if (fun1.FunctionSymbol.Equals(Prop.True)) { + return e0; + } else if (fun1.FunctionSymbol.Equals(Prop.False)) { + return e1; + } + } + + return factory.And(e0, e1); + } + + public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { + Contract.Requires(exprs != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr/*!*/ result = factory.True; + Contract.Assert(result != null); + foreach (IExpr/*!*/ conjunct in exprs) { + Contract.Assert(conjunct != null); + result = SimplifiedAnd(factory, result, conjunct); + } + return result; + } + + public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IFunApp fun0 = e0 as IFunApp; + if (fun0 != null) { + if (fun0.FunctionSymbol.Equals(Prop.False)) { + return e1; + } else if (fun0.FunctionSymbol.Equals(Prop.True)) { + return e0; + } + } + + IFunApp fun1 = e1 as IFunApp; + if (fun1 != null) { + if (fun1.FunctionSymbol.Equals(Prop.False)) { + return e0; + } else if (fun1.FunctionSymbol.Equals(Prop.True)) { + return e1; + } + } + + return factory.Or(e0, e1); + } + + public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IEnumerable/**//*!*/ exprs) { + Contract.Requires(exprs != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr/*!*/ result = factory.False; + Contract.Assert(result != null); + foreach (IExpr/*!*/ disj in exprs) { + Contract.Assert(disj != null); + result = SimplifiedOr(factory, result, disj); + } + return result; + } + + + + /// + /// Break top-level conjuncts into a list of sub-expressions. + /// + /// The expression to examine. + /// A list of conjuncts. + internal static IList/**//*!*/ BreakConjuncts(IExpr/*!*/ e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { + var sub = Contract.Result()[i]; + return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.And); + })); + return BreakJuncts(e, Prop.And); + } + + /// + /// Break top-level disjuncts into a list of sub-expressions. + /// + /// The expression to examine. + /// A list of conjuncts. + internal static IList/**//*!*/ BreakDisjuncts(IExpr/*!*/ e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { + var sub = Contract.Result()[i]; + return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.Or); + })); + return BreakJuncts(e, Prop.Or); + } + + private static IList/**//*!*/ BreakJuncts(IExpr/*!*/ e, IFunctionSymbol/*!*/ sym) { + Contract.Requires(sym != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result().Count, i => { + var sub = Contract.Result()[i]; + return (sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(sym); + })); + ArrayList/**//*!*/ result = new ArrayList(); + + IFunApp f = e as IFunApp; + if (f != null) { + // If it is a sym, go down into sub-expressions. + if (f.FunctionSymbol.Equals(sym)) { + foreach (IExpr/*!*/ arg in f.Arguments) { + Contract.Assert(arg != null); + result.AddRange(BreakJuncts(arg, sym)); + } + } + // Otherwise, stop. + else { + result.Add(e); + } + } else { + result.Add(e); + } + + return result; + } + } + + /// + /// A callback to produce a function body given the bound variable. + /// + /// The bound variable to use. + /// The function body. + public delegate IExpr/*!*/ FunctionBody(IVariable/*!*/ var); + + /// + /// An interface for constructing propositional expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(IPropExprFactoryContracts))] + public interface IPropExprFactory + { + IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } + IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } + + IFunApp/*!*/ Not(IExpr/*!*/ p) /*ensures result.FunctionSymbol.Equals(Prop.Not);*/; + + IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; + IFunApp/*!*/ Or(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Or);*/; + + IFunApp/*!*/ Implies(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.Implies);*/; + } + [ContractClassFor(typeof(IPropExprFactory))] + public abstract class IPropExprFactoryContracts : IPropExprFactory + { + #region IPropExprFactory Members + IFunApp IPropExprFactory.Implies(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.False { + + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp IPropExprFactory.True { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp IPropExprFactory.Not(IExpr p) { + Contract.Requires(p != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.And(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.Or(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + + + #endregion + } + + /// + /// An interface for constructing value expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(IValueExprFactoryContracts))] + public interface IValueExprFactory + { + IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; + IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; + } + [ContractClassFor(typeof(IValueExprFactory))] + public abstract class IValueExprFactoryContracts : IValueExprFactory + { + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for constructing value expressions having to with null. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(INullnessFactoryContracts))] + public interface INullnessFactory + { + IFunApp/*!*/ Eq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/; + IFunApp/*!*/ Neq(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/; + IFunApp/*!*/ Null { get; /*ensures result.FunctionSymbol.Equals(Ref.Null);*/ } + } + [ContractClassFor(typeof(INullnessFactory))] + public abstract class INullnessFactoryContracts : INullnessFactory + { + #region INullnessFactory Members + + IFunApp INullnessFactory.Eq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp INullnessFactory.Neq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp INullnessFactory.Null { + get { + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + } + + #endregion + } + + /// + /// An interface for constructing integer expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(IIntExprFactoryContracts))] + public interface IIntExprFactory : IValueExprFactory + { + IFunApp/*!*/ Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/; + } + [ContractClassFor(typeof(IIntExprFactory))] + public abstract class IIntExprFactoryContracts : IIntExprFactory + { + + #region IIntExprFactory Members + + IFunApp IIntExprFactory.Const(BigNum i) { + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for constructing linear integer expressions. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(ILinearExprFactoryContracts))] + public interface ILinearExprFactory : IIntExprFactory + { + IFunApp/*!*/ AtMost(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.AtMost);*/; + IFunApp/*!*/ Add(IExpr/*!*/ e0, IExpr/*!*/ e1) /*ensures result.FunctionSymbol.Equals(Value.Add);*/; + /// + /// If "var" is null, returns an expression representing r. + /// Otherwise, returns an expression representing r*var. + /// + IExpr/*!*/ Term(Microsoft.Basetypes.Rational r, IVariable var); + + IFunApp/*!*/ False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; } + IFunApp/*!*/ True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; } + IFunApp/*!*/ And(IExpr/*!*/ p, IExpr/*!*/ q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/; + } + [ContractClassFor(typeof(ILinearExprFactory))] + public abstract class ILinearExprFactoryContracts : ILinearExprFactory + { + + #region ILinearExprFactory Members + + IFunApp ILinearExprFactory.AtMost(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ILinearExprFactory.Add(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IExpr ILinearExprFactory.Term(Rational r, IVariable var) { + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ILinearExprFactory.False { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp ILinearExprFactory.True { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + IFunApp ILinearExprFactory.And(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + + #region IIntExprFactory Members + + IFunApp IIntExprFactory.Const(BigNum i) { + throw new System.NotImplementedException(); + } + + #endregion + + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for constructing type expressions and performing some type operations. + /// The types are assumed to be arranged in a rooted tree. + /// + /// This interface should be implemented by the client. An implementation of + /// of this class should generally be used as a singleton object. + /// + /// + [ContractClass(typeof(ITypeExprFactoryContracts))] + public interface ITypeExprFactory + { + /// + /// Returns an expression denoting the top of the type hierarchy. + /// + IExpr/*!*/ RootType { get; } + + /// + /// Returns true iff "t" denotes a type constant. + /// + [Pure] + bool IsTypeConstant(IExpr/*!*/ t); + + /// + /// Returns true iff t0 and t1 are types such that t0 and t1 are equal. + /// + [Pure] + bool IsTypeEqual(IExpr/*!*/ t0, IExpr/*!*/ t1); + + /// + /// Returns true iff t0 and t1 are types such that t0 is a subtype of t1. + /// + [Pure] + bool IsSubType(IExpr/*!*/ t0, IExpr/*!*/ t1); + + /// + /// Returns the most derived supertype of both "t0" and "t1". A precondition is + /// that "t0" and "t1" both represent types. + /// + IExpr/*!*/ JoinTypes(IExpr/*!*/ t0, IExpr/*!*/ t1); + + IFunApp/*!*/ IsExactlyA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Eq);*/; + IFunApp/*!*/ IsA(IExpr/*!*/ e, IExpr/*!*/ type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Subtype);*/; + } + [ContractClassFor(typeof(ITypeExprFactory))] + public abstract class ITypeExprFactoryContracts : ITypeExprFactory + { + + #region ITypeExprFactory Members + + IExpr ITypeExprFactory.RootType { + get { Contract.Ensures(Contract.Result() != null); throw new System.NotImplementedException(); } + } + + bool ITypeExprFactory.IsTypeConstant(IExpr t) { + Contract.Requires(t != null); + throw new System.NotImplementedException(); + } + + bool ITypeExprFactory.IsTypeEqual(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + throw new System.NotImplementedException(); + } + + bool ITypeExprFactory.IsSubType(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + throw new System.NotImplementedException(); + } + + IExpr ITypeExprFactory.JoinTypes(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ITypeExprFactory.IsExactlyA(IExpr e, IExpr type) { + Contract.Requires(e != null); + Contract.Requires(type != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + IFunApp ITypeExprFactory.IsA(IExpr e, IExpr type) { + Contract.Requires(e != null); + Contract.Requires(type != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + + #endregion + } +} diff --git a/Source/AIFramework/Expr.cs b/Source/AIFramework/Expr.cs index 58473592..ae2bd4b7 100644 --- a/Source/AIFramework/Expr.cs +++ b/Source/AIFramework/Expr.cs @@ -1,640 +1,640 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -// This file specifies the expression language used by the Abstract -// Interpretation Framework. -// -// expressions e ::= x variables -// | f(e1,...,en) uninterpreted functions -// | \x:t.e lambda expressions -// -// types t ::= b user-defined/built-in base types -// | t1 * ... * tn -> t' function type - -namespace Microsoft.AbstractInterpretationFramework -{ - using System.Collections; - using System; - using System.Diagnostics.Contracts; - - //----------------------------- Expressions ----------------------------- - - /// - /// An interface for expressions. This expression language is specified - /// by interfaces to allow the client to be able to use their existing - /// AST nodes as AIF expressions. - /// - /// This only serves as a place for operations on expressions. Clients - /// should implement directly IVariable, IFunApp, ... - /// - [ContractClass(typeof(IExprContracts))] - public interface IExpr - { - /// - /// Execute a visit over the expression. - /// - /// The expression visitor. - /// The result of the visit. - [Pure] object DoVisit(ExprVisitor/*!*/ visitor); - - // TODO: Type checking of the expressions. - } - [ContractClassFor(typeof(IExpr))] - public abstract class IExprContracts:IExpr{ - #region IExpr Members - -public object DoVisit(ExprVisitor visitor) -{ - Contract.Requires(visitor != null); - throw new System.NotImplementedException(); -} - -#endregion -} - - /// - /// An interface for variables. - /// - /// This interface should be implemented by the client. - /// - [ContractClass(typeof(IVariableContracts))] - public interface IVariable : IExpr - { - string/*!*/ Name { get; } // Each client must define the name for variables - } - [ContractClassFor(typeof(IVariable))] - public abstract class IVariableContracts:IVariable{ - string IVariable.Name{get{Contract.Ensures(Contract.Result() != null);throw new NotImplementedException();} - - } - - #region IExpr Members - - object IExpr.DoVisit(ExprVisitor visitor) { - throw new NotImplementedException(); - } - - #endregion - } - - /// - /// An interface for function applications. - /// - /// This interface should be implemented by the client. - /// - /// - [ContractClass(typeof(IFunAppContracts))] - public interface IFunApp : IExpr - { - IFunctionSymbol/*!*/ FunctionSymbol { get; } - IList/**//*!*/ Arguments - { - [Pure][Rep] get; - - } - - /// - /// Provides a method to create a new uninterpreted function - /// with the same function symbol but with the arguments with - /// args. - /// - /// The new arguments. - /// A copy of the function with the new arguments. - IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) - //TODO Contract.Requires(this.Arguments.Count == args.Count); - ; - } - [ContractClassFor(typeof(IFunApp))] -public abstract class IFunAppContracts:IFunApp{ - -#region IFunApp Members - -public IFunctionSymbol FunctionSymbol -{ - get {Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); } -} - -public IList Arguments -{ - get {Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().IsReadOnly); - throw new System.NotImplementedException(); } -} - -public IFunApp CloneWithArguments(IList args) -{ - Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - - - throw new System.NotImplementedException(); -} - -#endregion - -#region IExpr Members - -object IExpr.DoVisit(ExprVisitor visitor) { - throw new NotImplementedException(); -} - -#endregion -} - - /// - /// An interface for anonymous functions (i.e., lambda expressions) - /// - [ContractClass(typeof(IFunctionContracts))] - public interface IFunction : IExpr - { - IVariable/*!*/ Param { get; } - AIType/*!*/ ParamType { get; } - IExpr/*!*/ Body { get; } - - IFunction/*!*/ CloneWithBody(IExpr/*!*/ body); - } - [ContractClassFor(typeof(IFunction))] - public abstract class IFunctionContracts:IFunction{ - - #region IFunction Members - - IVariable IFunction.Param { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - AIType IFunction.ParamType { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - IExpr IFunction.Body { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - IFunction IFunction.CloneWithBody(IExpr body) { - Contract.Requires(body != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - #endregion - - #region IExpr Members - - object IExpr.DoVisit(ExprVisitor visitor) { - throw new NotImplementedException(); - } - - #endregion - } - - /// - /// An interface representing an expression that at any moment could, in principle, evaluate - /// to a different value. That is, the abstract interpreter should treat these IExpr's - /// as unknown values. They are used when there is no other IExpr corresponding to the - /// expression to be modeled. - /// - public interface IUnknown : IExpr {} - - /// - /// An abstract class that provides an interface for expression visitors. - /// - [ContractClass(typeof(ExprVisitorContracts))] - public abstract class ExprVisitor - { - public abstract object Default(IExpr/*!*/ expr); - - public virtual object VisitVariable(IVariable/*!*/ var){ -Contract.Requires(var != null); - return Default(var); - } - - public virtual object VisitFunApp(IFunApp/*!*/ funapp){ -Contract.Requires(funapp != null); - return Default(funapp); - } - - public virtual object VisitFunction(IFunction/*!*/ fun){ -Contract.Requires(fun != null); - return Default(fun); - } - } - [ContractClassFor(typeof(ExprVisitor))] - public abstract class ExprVisitorContracts:ExprVisitor{ - public override object Default(IExpr expr) -{ - Contract.Requires(expr != null); throw new NotImplementedException(); -}} - - /// - /// A utility class for dealing with expressions. - /// - public sealed class ExprUtil - { - /// - /// Yield an expression that is 'inexpr' with 'var' replaced by 'subst'. - /// - /// The expression to substitute. - /// The variable to substitute for. - /// The expression to substitute into. - public static IExpr/*!*/ Substitute(IExpr/*!*/ subst, IVariable/*!*/ var, IExpr/*!*/ inexpr){ -Contract.Requires(inexpr != null); -Contract.Requires(var != null); -Contract.Requires(subst != null); -Contract.Ensures(Contract.Result() != null); - IExpr result = null; - - if (inexpr is IVariable) - { - result = inexpr.Equals(var) ? subst : inexpr; - } - else if (inexpr is IFunApp) - { - IFunApp/*!*/ funapp = (IFunApp/*!*/)cce.NonNull(inexpr); - IList newargs = null; - - var x = new System.Collections.Generic.List(); - foreach (IExpr arg in funapp.Arguments){ - x.Add(Substitute(subst,var, arg)); - } - newargs = new ArrayList(x); - //newargs = new ArrayList{ IExpr/*!*/ arg in funapp.Arguments; Substitute(subst, var, arg) }; - result = funapp.CloneWithArguments(newargs); - } - else if (inexpr is IFunction) - { - IFunction/*!*/ fun = (IFunction/*!*/)cce.NonNull(inexpr); - - if (fun.Param.Equals(var)) - result = fun; - else - result = fun.CloneWithBody(Substitute(subst, var, fun.Body)); - } - else if (inexpr is IUnknown) - { - result = inexpr; - } - else - { - {Contract.Assert(false);throw new cce.UnreachableException();} - } - - return result; - } - - - // - // Poor man's pattern matching. - // - // The methods below implement pattern matching for AI expressions. - // - // Example Usage: - // Match(e, Prop.Imp, - // (Matcher)delegate (IExpr e) { return Match(e, Prop.And, out x, out y); } - // out z) - // which sees if 'e' matches Prop.Imp(Prop.And(x,y),z) binding x,y,z to the subtrees. - // - public delegate bool Matcher(IExpr/*!*/ expr); - - private static IFunApp/*?*/ MatchFunctionSymbol(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f){ -Contract.Requires(f != null); -Contract.Requires(expr != null); - IFunApp app = expr as IFunApp; - if (app != null) - { - if (app.FunctionSymbol.Equals(f)) - return app; - else - return null; - } - else - return null; - } - - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - int i = 0; // Note ***0*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - // Unary Binding - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg0 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); - - int i = 1; // Note ***1*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - // Binary Binding - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, Matcher/*!*/ sub0, out IExpr arg1, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(sub0 != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg1 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - if (!sub0(cce.NonNull((IExpr/*!*/)app.Arguments[0]))) { return false; } - - arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); - - int i = 2; // Note ***2*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg0 = null; - arg1 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); - arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); - - int i = 2; // Note ***2*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - // Ternary Binding - public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, out IExpr arg2, params Matcher[]/*!*/ subs){ -Contract.Requires(subs != null); -Contract.Requires(f != null); -Contract.Requires(expr != null); - arg0 = null; - arg1 = null; - arg2 = null; - - IFunApp app = MatchFunctionSymbol(expr,f); - if (app != null) - { - arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); - arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); - arg2 = (IExpr/*!*/)cce.NonNull(app.Arguments[2]); - - int i = 3; // Note ***3*** - foreach(Matcher/*!*/ s in subs){ -Contract.Assert(s != null); - if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } - i++; - } - return true; - } - else { return false; } - } - - /// - /// Not intended to be instantiated. - /// - private ExprUtil() { } - } - - //------------------------------ Symbols -------------------------------- - - /// - /// An interface for function symbols. Constants are represented by - /// 0-ary function symbols. - /// - /// This interface should be implemented by abstract domains, but client - /// expressions need keep track of function symbols. - /// - [ContractClass(typeof(IFunctionSymbolContracts))] - public interface IFunctionSymbol - { - AIType/*!*/ AIType { [Rep][ResultNotNewlyAllocated] - get; } - } - [ContractClassFor(typeof(IFunctionSymbol))] - public abstract class IFunctionSymbolContracts:IFunctionSymbol{ - #region IFunctionSymbol Members - - AIType IFunctionSymbol.AIType { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - #endregion - } - - /// - /// The type of the arguments to ExprUtil.Match, a poor man's pattern - /// matching. - /// - public interface IMatchable - { - } - - //-------------------------------- Types -------------------------------- - - /// - /// Types. - /// - public interface AIType - { - } - - /// - /// Function type constructor. - /// - public sealed class FunctionType : AIType - { - /*[Own]*/ private readonly IList/**//*!*/ argTypes; - /*[Own]*/ private readonly AIType/*!*/ retType; - [ContractInvariantMethod] -void ObjectInvariant() -{ - Contract.Invariant(argTypes != null); - Contract.Invariant(retType != null); -} - - - public FunctionType(params AIType[]/*!*/ types){ -Contract.Requires(types != null); - Contract.Requires(types.Length >= 2); - AIType type = types[types.Length-1]; - Contract.Assume(type != null); - this.retType = type; - ArrayList argTypes = new ArrayList(); - for (int i = 0; i < types.Length-1; i++) - { - type = types[i]; - Contract.Assume(type != null); - argTypes.Add(types); - } - this.argTypes = ArrayList.ReadOnly(argTypes); - } - - public IList/**//*!*/ Arguments - { - [Pure][Rep] - get - { - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().IsReadOnly); - return argTypes; - } - } - - public int Arity - { - get { return argTypes.Count; } - } - - public AIType/*!*/ ReturnType - { - get {Contract.Ensures(Contract.Result() != null); return retType; } - } - - /* TODO Do we have the invariant that two functions are equal iff they're the same object. - public override bool Equals(object o) - { - if (o != null && o is FunctionType) - { - FunctionType other = (FunctionType) o; - - if (Arity == other.Arity - && ReturnType.Equals(other.ReturnType)) - { - for (int i = 0; i < Arity; i++) - { - if (!argTypes[i].Equals(other.argTypes[i])) - return false; - } - return true; - } - else - return false; - } - else - return false; - } - */ - } - - //------------------------------ Queries ------------------------------- - - public enum Answer { Yes, No, Maybe }; - - /// - /// An interface that specifies a queryable object that can answer - /// whether a predicate holds. - /// - /// - [ContractClass(typeof(IQueryableContracts))] - public interface IQueryable - { - /// - /// Answers the query whether the given predicate holds. - /// - /// The given predicate. - /// Yes, No, or Maybe. - Answer CheckPredicate(IExpr/*!*/ pred); - - /// - /// A simplified interface for disequalities. One can always - /// implement this by calling CheckPredicate, but it may be - /// more efficient with this method. - /// - Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2); - } - [ContractClassFor(typeof(IQueryable))] - public abstract class IQueryableContracts : IQueryable { - #region IQueryable Members - - public Answer CheckPredicate(IExpr pred) { - Contract.Requires(pred != null); - throw new NotImplementedException(); - } - - public Answer CheckVariableDisequality(IVariable var1, IVariable var2) { - Contract.Requires(var1 != null); - Contract.Requires(var2 != null); - throw new NotImplementedException(); - } - - #endregion - } - - public static class QueryUtil - { - public static Answer Negate(Answer ans) - { - switch (ans) - { - case Answer.Yes: - return Answer.No; - case Answer.No: - return Answer.Yes; - default: - return Answer.Maybe; - } - } - } - - //----------------------------- Exceptions ----------------------------- - - public class CheckedException : System.Exception { - } - public class TypeError : CheckedException - { - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +// This file specifies the expression language used by the Abstract +// Interpretation Framework. +// +// expressions e ::= x variables +// | f(e1,...,en) uninterpreted functions +// | \x:t.e lambda expressions +// +// types t ::= b user-defined/built-in base types +// | t1 * ... * tn -> t' function type + +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Collections; + using System; + using System.Diagnostics.Contracts; + + //----------------------------- Expressions ----------------------------- + + /// + /// An interface for expressions. This expression language is specified + /// by interfaces to allow the client to be able to use their existing + /// AST nodes as AIF expressions. + /// + /// This only serves as a place for operations on expressions. Clients + /// should implement directly IVariable, IFunApp, ... + /// + [ContractClass(typeof(IExprContracts))] + public interface IExpr + { + /// + /// Execute a visit over the expression. + /// + /// The expression visitor. + /// The result of the visit. + [Pure] object DoVisit(ExprVisitor/*!*/ visitor); + + // TODO: Type checking of the expressions. + } + [ContractClassFor(typeof(IExpr))] + public abstract class IExprContracts:IExpr{ + #region IExpr Members + +public object DoVisit(ExprVisitor visitor) +{ + Contract.Requires(visitor != null); + throw new System.NotImplementedException(); +} + +#endregion +} + + /// + /// An interface for variables. + /// + /// This interface should be implemented by the client. + /// + [ContractClass(typeof(IVariableContracts))] + public interface IVariable : IExpr + { + string/*!*/ Name { get; } // Each client must define the name for variables + } + [ContractClassFor(typeof(IVariable))] + public abstract class IVariableContracts:IVariable{ + string IVariable.Name{get{Contract.Ensures(Contract.Result() != null);throw new NotImplementedException();} + + } + + #region IExpr Members + + object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); + } + + #endregion + } + + /// + /// An interface for function applications. + /// + /// This interface should be implemented by the client. + /// + /// + [ContractClass(typeof(IFunAppContracts))] + public interface IFunApp : IExpr + { + IFunctionSymbol/*!*/ FunctionSymbol { get; } + IList/**//*!*/ Arguments + { + [Pure][Rep] get; + + } + + /// + /// Provides a method to create a new uninterpreted function + /// with the same function symbol but with the arguments with + /// args. + /// + /// The new arguments. + /// A copy of the function with the new arguments. + IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) + //TODO Contract.Requires(this.Arguments.Count == args.Count); + ; + } + [ContractClassFor(typeof(IFunApp))] +public abstract class IFunAppContracts:IFunApp{ + +#region IFunApp Members + +public IFunctionSymbol FunctionSymbol +{ + get {Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); } +} + +public IList Arguments +{ + get {Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result().IsReadOnly); + throw new System.NotImplementedException(); } +} + +public IFunApp CloneWithArguments(IList args) +{ + Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + + + throw new System.NotImplementedException(); +} + +#endregion + +#region IExpr Members + +object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); +} + +#endregion +} + + /// + /// An interface for anonymous functions (i.e., lambda expressions) + /// + [ContractClass(typeof(IFunctionContracts))] + public interface IFunction : IExpr + { + IVariable/*!*/ Param { get; } + AIType/*!*/ ParamType { get; } + IExpr/*!*/ Body { get; } + + IFunction/*!*/ CloneWithBody(IExpr/*!*/ body); + } + [ContractClassFor(typeof(IFunction))] + public abstract class IFunctionContracts:IFunction{ + + #region IFunction Members + + IVariable IFunction.Param { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + AIType IFunction.ParamType { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + IExpr IFunction.Body { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + IFunction IFunction.CloneWithBody(IExpr body) { + Contract.Requires(body != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + #endregion + + #region IExpr Members + + object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); + } + + #endregion + } + + /// + /// An interface representing an expression that at any moment could, in principle, evaluate + /// to a different value. That is, the abstract interpreter should treat these IExpr's + /// as unknown values. They are used when there is no other IExpr corresponding to the + /// expression to be modeled. + /// + public interface IUnknown : IExpr {} + + /// + /// An abstract class that provides an interface for expression visitors. + /// + [ContractClass(typeof(ExprVisitorContracts))] + public abstract class ExprVisitor + { + public abstract object Default(IExpr/*!*/ expr); + + public virtual object VisitVariable(IVariable/*!*/ var){ +Contract.Requires(var != null); + return Default(var); + } + + public virtual object VisitFunApp(IFunApp/*!*/ funapp){ +Contract.Requires(funapp != null); + return Default(funapp); + } + + public virtual object VisitFunction(IFunction/*!*/ fun){ +Contract.Requires(fun != null); + return Default(fun); + } + } + [ContractClassFor(typeof(ExprVisitor))] + public abstract class ExprVisitorContracts:ExprVisitor{ + public override object Default(IExpr expr) +{ + Contract.Requires(expr != null); throw new NotImplementedException(); +}} + + /// + /// A utility class for dealing with expressions. + /// + public sealed class ExprUtil + { + /// + /// Yield an expression that is 'inexpr' with 'var' replaced by 'subst'. + /// + /// The expression to substitute. + /// The variable to substitute for. + /// The expression to substitute into. + public static IExpr/*!*/ Substitute(IExpr/*!*/ subst, IVariable/*!*/ var, IExpr/*!*/ inexpr){ +Contract.Requires(inexpr != null); +Contract.Requires(var != null); +Contract.Requires(subst != null); +Contract.Ensures(Contract.Result() != null); + IExpr result = null; + + if (inexpr is IVariable) + { + result = inexpr.Equals(var) ? subst : inexpr; + } + else if (inexpr is IFunApp) + { + IFunApp/*!*/ funapp = (IFunApp/*!*/)cce.NonNull(inexpr); + IList newargs = null; + + var x = new System.Collections.Generic.List(); + foreach (IExpr arg in funapp.Arguments){ + x.Add(Substitute(subst,var, arg)); + } + newargs = new ArrayList(x); + //newargs = new ArrayList{ IExpr/*!*/ arg in funapp.Arguments; Substitute(subst, var, arg) }; + result = funapp.CloneWithArguments(newargs); + } + else if (inexpr is IFunction) + { + IFunction/*!*/ fun = (IFunction/*!*/)cce.NonNull(inexpr); + + if (fun.Param.Equals(var)) + result = fun; + else + result = fun.CloneWithBody(Substitute(subst, var, fun.Body)); + } + else if (inexpr is IUnknown) + { + result = inexpr; + } + else + { + {Contract.Assert(false);throw new cce.UnreachableException();} + } + + return result; + } + + + // + // Poor man's pattern matching. + // + // The methods below implement pattern matching for AI expressions. + // + // Example Usage: + // Match(e, Prop.Imp, + // (Matcher)delegate (IExpr e) { return Match(e, Prop.And, out x, out y); } + // out z) + // which sees if 'e' matches Prop.Imp(Prop.And(x,y),z) binding x,y,z to the subtrees. + // + public delegate bool Matcher(IExpr/*!*/ expr); + + private static IFunApp/*?*/ MatchFunctionSymbol(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f){ +Contract.Requires(f != null); +Contract.Requires(expr != null); + IFunApp app = expr as IFunApp; + if (app != null) + { + if (app.FunctionSymbol.Equals(f)) + return app; + else + return null; + } + else + return null; + } + + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + int i = 0; // Note ***0*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + // Unary Binding + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + + int i = 1; // Note ***1*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + // Binary Binding + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, Matcher/*!*/ sub0, out IExpr arg1, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(sub0 != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg1 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + if (!sub0(cce.NonNull((IExpr/*!*/)app.Arguments[0]))) { return false; } + + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + + int i = 2; // Note ***2*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + arg1 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + + int i = 2; // Note ***2*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + // Ternary Binding + public static bool Match(IExpr/*!*/ expr, IFunctionSymbol/*!*/ f, out IExpr arg0, out IExpr arg1, out IExpr arg2, params Matcher[]/*!*/ subs){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + arg1 = null; + arg2 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + arg2 = (IExpr/*!*/)cce.NonNull(app.Arguments[2]); + + int i = 3; // Note ***3*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((IExpr/*!*/)app.Arguments[i]))) { return false; } + i++; + } + return true; + } + else { return false; } + } + + /// + /// Not intended to be instantiated. + /// + private ExprUtil() { } + } + + //------------------------------ Symbols -------------------------------- + + /// + /// An interface for function symbols. Constants are represented by + /// 0-ary function symbols. + /// + /// This interface should be implemented by abstract domains, but client + /// expressions need keep track of function symbols. + /// + [ContractClass(typeof(IFunctionSymbolContracts))] + public interface IFunctionSymbol + { + AIType/*!*/ AIType { [Rep][ResultNotNewlyAllocated] + get; } + } + [ContractClassFor(typeof(IFunctionSymbol))] + public abstract class IFunctionSymbolContracts:IFunctionSymbol{ + #region IFunctionSymbol Members + + AIType IFunctionSymbol.AIType { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + #endregion + } + + /// + /// The type of the arguments to ExprUtil.Match, a poor man's pattern + /// matching. + /// + public interface IMatchable + { + } + + //-------------------------------- Types -------------------------------- + + /// + /// Types. + /// + public interface AIType + { + } + + /// + /// Function type constructor. + /// + public sealed class FunctionType : AIType + { + /*[Own]*/ private readonly IList/**//*!*/ argTypes; + /*[Own]*/ private readonly AIType/*!*/ retType; + [ContractInvariantMethod] +void ObjectInvariant() +{ + Contract.Invariant(argTypes != null); + Contract.Invariant(retType != null); +} + + + public FunctionType(params AIType[]/*!*/ types){ +Contract.Requires(types != null); + Contract.Requires(types.Length >= 2); + AIType type = types[types.Length-1]; + Contract.Assume(type != null); + this.retType = type; + ArrayList argTypes = new ArrayList(); + for (int i = 0; i < types.Length-1; i++) + { + type = types[i]; + Contract.Assume(type != null); + argTypes.Add(types); + } + this.argTypes = ArrayList.ReadOnly(argTypes); + } + + public IList/**//*!*/ Arguments + { + [Pure][Rep] + get + { + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result().IsReadOnly); + return argTypes; + } + } + + public int Arity + { + get { return argTypes.Count; } + } + + public AIType/*!*/ ReturnType + { + get {Contract.Ensures(Contract.Result() != null); return retType; } + } + + /* TODO Do we have the invariant that two functions are equal iff they're the same object. + public override bool Equals(object o) + { + if (o != null && o is FunctionType) + { + FunctionType other = (FunctionType) o; + + if (Arity == other.Arity + && ReturnType.Equals(other.ReturnType)) + { + for (int i = 0; i < Arity; i++) + { + if (!argTypes[i].Equals(other.argTypes[i])) + return false; + } + return true; + } + else + return false; + } + else + return false; + } + */ + } + + //------------------------------ Queries ------------------------------- + + public enum Answer { Yes, No, Maybe }; + + /// + /// An interface that specifies a queryable object that can answer + /// whether a predicate holds. + /// + /// + [ContractClass(typeof(IQueryableContracts))] + public interface IQueryable + { + /// + /// Answers the query whether the given predicate holds. + /// + /// The given predicate. + /// Yes, No, or Maybe. + Answer CheckPredicate(IExpr/*!*/ pred); + + /// + /// A simplified interface for disequalities. One can always + /// implement this by calling CheckPredicate, but it may be + /// more efficient with this method. + /// + Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2); + } + [ContractClassFor(typeof(IQueryable))] + public abstract class IQueryableContracts : IQueryable { + #region IQueryable Members + + public Answer CheckPredicate(IExpr pred) { + Contract.Requires(pred != null); + throw new NotImplementedException(); + } + + public Answer CheckVariableDisequality(IVariable var1, IVariable var2) { + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + throw new NotImplementedException(); + } + + #endregion + } + + public static class QueryUtil + { + public static Answer Negate(Answer ans) + { + switch (ans) + { + case Answer.Yes: + return Answer.No; + case Answer.No: + return Answer.Yes; + default: + return Answer.Maybe; + } + } + } + + //----------------------------- Exceptions ----------------------------- + + public class CheckedException : System.Exception { + } + public class TypeError : CheckedException + { + } +} diff --git a/Source/AIFramework/Functional.cs b/Source/AIFramework/Functional.cs index 3b8237bf..51d8562a 100644 --- a/Source/AIFramework/Functional.cs +++ b/Source/AIFramework/Functional.cs @@ -1,430 +1,430 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; - -namespace Microsoft.AbstractInterpretationFramework.Collections { - using System.Collections; - - /// Represents a functional collection of key/value pairs. - /// 2 - [ContractClass(typeof(IFunctionalMapContracts))] - public interface IFunctionalMap : System.Collections.ICollection, System.Collections.IEnumerable { - /// Adds an element with the provided key and value to the . - /// The to use as the value of the element to add. - /// The to use as the key of the element to add. - /// 2 - IFunctionalMap/*!*/ Add(object/*!*/ key, object value); - - /// - /// Set the value of the key (that is already in the map) - /// - IFunctionalMap/*!*/ Set(object/*!*/ key, object value); - - /// Determines whether the contains an element with the specified key. - /// true if the contains an element with the key; otherwise, false. - /// The key to locate in the . - /// 2 - [Pure] - bool Contains(object/*!*/ key); - - /// Returns an for the . - /// An for the . - /// 2 - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - new System.Collections.IDictionaryEnumerator GetEnumerator(); - - /// Gets an containing the keys of the . - /// An containing the keys of the . - /// 2 - System.Collections.ICollection Keys { - get; - } - - /// Removes the element with the specified key from the . - /// The key of the element to remove. - /// 2 - IFunctionalMap/*!*/ Remove(object/*!*/ key); - - /// Gets an containing the values in the . - /// An containing the values in the . - /// 2 - System.Collections.ICollection Values { - get; - } - - object this[object/*!*/ key] { - get; /*set;*/ - } - } - [ContractClassFor(typeof(IFunctionalMap))] - public abstract class IFunctionalMapContracts : IFunctionalMap { - - #region IFunctionalMap Members - - IFunctionalMap IFunctionalMap.Add(object key, object value) { - Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - - throw new System.NotImplementedException(); - } - - IFunctionalMap IFunctionalMap.Set(object key, object value) { - Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - - throw new System.NotImplementedException(); - } - - bool IFunctionalMap.Contains(object key) { - Contract.Requires(key != null); - - throw new System.NotImplementedException(); - } - - IDictionaryEnumerator IFunctionalMap.GetEnumerator() { - throw new System.NotImplementedException(); - } - - ICollection IFunctionalMap.Keys { - get { - throw new System.NotImplementedException(); - } - } - - IFunctionalMap IFunctionalMap.Remove(object key) { - Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - - throw new System.NotImplementedException(); - } - - ICollection IFunctionalMap.Values { - get { - throw new System.NotImplementedException(); - } - } - - object IFunctionalMap.this[object key] { - get { - Contract.Requires(key != null); - throw new System.NotImplementedException(); - } - } - - #endregion - - #region ICollection Members - - void ICollection.CopyTo(System.Array array, int index) { - throw new System.NotImplementedException(); - } - - int ICollection.Count { - get { - throw new System.NotImplementedException(); - } - } - - bool ICollection.IsSynchronized { - get { - throw new System.NotImplementedException(); - } - } - - object ICollection.SyncRoot { - get { - throw new System.NotImplementedException(); - } - } - - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() { - throw new System.NotImplementedException(); - } - - #endregion - } - - - - /// - /// An implementation of the - /// - /// interface with a as the backing store. - /// - class FunctionalHashtable : IFunctionalMap { - private readonly Hashtable/*!*/ h; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(h != null); - } - - - /// - /// Cannot directly construct an instance of a FunctionalHashtbl. - /// - private FunctionalHashtable() { - this.h = new Hashtable(); - // base(); - } - - /// - /// Cannot directly construct an instance of a FunctionalHashtbl. - /// - private FunctionalHashtable(Hashtable/*!*/ h) { - Contract.Requires(h != null); - this.h = h; - // base(); - } - - private static readonly IFunctionalMap/*!*/ empty = new FunctionalHashtable(); - public static IFunctionalMap/*!*/ Empty { - get { - Contract.Ensures(Contract.Result() != null); - return empty; - } - } - - public IFunctionalMap/*!*/ Add(object/*!*/ key, object value) { - //Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - Hashtable r = h.Clone() as Hashtable; - Contract.Assume(r != null); - r.Add(key, value); - return new FunctionalHashtable(r); - } - - public IFunctionalMap/*!*/ Set(object/*!*/ key, object value) { - //Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - Hashtable r = h.Clone() as Hashtable; - - Contract.Assume(r != null); - Contract.Assert(this.Contains(key)); // The entry must be defined - - r[key] = value; - return new FunctionalHashtable(r); - } - - [Pure] - public bool Contains(object/*!*/ key) { - //Contract.Requires(key != null); - return h.Contains(key); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - IEnumerator/*!*/ IEnumerable.GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - - return h.GetEnumerator(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - IDictionaryEnumerator IFunctionalMap.GetEnumerator() { - return h.GetEnumerator(); - } - - public ICollection Keys { - get { - return h.Keys; - } - } - - public IFunctionalMap/*!*/ Remove(object/*!*/ key) { - //Contract.Requires(key != null); - Contract.Ensures(Contract.Result() != null); - Hashtable r = h.Clone() as Hashtable; - Contract.Assume(r != null); - r.Remove(key); - return new FunctionalHashtable(r); - } - - public ICollection Values { - get { - return h.Values; - } - } - - - public object this[object/*!*/ key] { - get { - //Contract.Requires(key != null); - return h[key]; - } - } - - public int Count { - [Pure] - get { - return h.Count; - } - } - - public bool IsSynchronized { - [Pure] - get { - return h.IsSynchronized; - } - } - - public object/*!*/ SyncRoot { - [Pure] - get { - Contract.Ensures(Contract.Result() != null); - return h.SyncRoot; - } - } - - public void CopyTo(System.Array/*!*/ a, int index) { - //Contract.Requires(a != null); - h.CopyTo(a, index); - } - } - - public struct Pair/**/ - { - private object first; - private object second; - - public object First { - get { - return first; - } - } - public object Second { - get { - return second; - } - } - - public Pair(object first, object second) { - this.first = first; - this.second = second; - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is Pair)) - return false; - - Pair other = (Pair)obj; - return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); - } - - public override int GetHashCode() { - int h = this.first == null ? 0 : this.first.GetHashCode(); - h ^= this.second == null ? 0 : this.second.GetHashCode(); - return h; - } - } -} - - -namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { - using System.Collections.Generic; - - public struct Pair { - private T1 first; - private T2 second; - - public T1 First { - get { - return first; - } - } - public T2 Second { - get { - return second; - } - } - - public Pair(T1 first, T2 second) { - this.first = first; - this.second = second; - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is Pair)) - return false; - - Pair other = (Pair)obj; - return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); - } - - public override int GetHashCode() { - int h = this.first == null ? 0 : this.first.GetHashCode(); - h ^= this.second == null ? 0 : this.second.GetHashCode(); - return h; - } - - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format("({0},{1})", first, second); - } - } - - public struct Triple { - private T1 first; - private T2 second; - private T3 third; - - public T1 First { - get { - return first; - } - } - public T2 Second { - get { - return second; - } - } - public T3 Third { - get { - return third; - } - } - - public Triple(T1 first, T2 second, T3 third) { - this.first = first; - this.second = second; - this.third = third; - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is Triple)) - return false; - - Triple other = (Triple)obj; - return object.Equals(this.first, other.first) && object.Equals(this.second, other.second) && object.Equals(this.third, other.third); - } - - public override int GetHashCode() { - int h = this.first == null ? 0 : this.first.GetHashCode(); - h ^= this.second == null ? 0 : this.second.GetHashCode(); - h ^= this.third == null ? 0 : this.third.GetHashCode(); - return h; - } - - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format("({0},{1},{2})", first, second, third); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; + +namespace Microsoft.AbstractInterpretationFramework.Collections { + using System.Collections; + + /// Represents a functional collection of key/value pairs. + /// 2 + [ContractClass(typeof(IFunctionalMapContracts))] + public interface IFunctionalMap : System.Collections.ICollection, System.Collections.IEnumerable { + /// Adds an element with the provided key and value to the . + /// The to use as the value of the element to add. + /// The to use as the key of the element to add. + /// 2 + IFunctionalMap/*!*/ Add(object/*!*/ key, object value); + + /// + /// Set the value of the key (that is already in the map) + /// + IFunctionalMap/*!*/ Set(object/*!*/ key, object value); + + /// Determines whether the contains an element with the specified key. + /// true if the contains an element with the key; otherwise, false. + /// The key to locate in the . + /// 2 + [Pure] + bool Contains(object/*!*/ key); + + /// Returns an for the . + /// An for the . + /// 2 + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + new System.Collections.IDictionaryEnumerator GetEnumerator(); + + /// Gets an containing the keys of the . + /// An containing the keys of the . + /// 2 + System.Collections.ICollection Keys { + get; + } + + /// Removes the element with the specified key from the . + /// The key of the element to remove. + /// 2 + IFunctionalMap/*!*/ Remove(object/*!*/ key); + + /// Gets an containing the values in the . + /// An containing the values in the . + /// 2 + System.Collections.ICollection Values { + get; + } + + object this[object/*!*/ key] { + get; /*set;*/ + } + } + [ContractClassFor(typeof(IFunctionalMap))] + public abstract class IFunctionalMapContracts : IFunctionalMap { + + #region IFunctionalMap Members + + IFunctionalMap IFunctionalMap.Add(object key, object value) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + + throw new System.NotImplementedException(); + } + + IFunctionalMap IFunctionalMap.Set(object key, object value) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + + throw new System.NotImplementedException(); + } + + bool IFunctionalMap.Contains(object key) { + Contract.Requires(key != null); + + throw new System.NotImplementedException(); + } + + IDictionaryEnumerator IFunctionalMap.GetEnumerator() { + throw new System.NotImplementedException(); + } + + ICollection IFunctionalMap.Keys { + get { + throw new System.NotImplementedException(); + } + } + + IFunctionalMap IFunctionalMap.Remove(object key) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + + throw new System.NotImplementedException(); + } + + ICollection IFunctionalMap.Values { + get { + throw new System.NotImplementedException(); + } + } + + object IFunctionalMap.this[object key] { + get { + Contract.Requires(key != null); + throw new System.NotImplementedException(); + } + } + + #endregion + + #region ICollection Members + + void ICollection.CopyTo(System.Array array, int index) { + throw new System.NotImplementedException(); + } + + int ICollection.Count { + get { + throw new System.NotImplementedException(); + } + } + + bool ICollection.IsSynchronized { + get { + throw new System.NotImplementedException(); + } + } + + object ICollection.SyncRoot { + get { + throw new System.NotImplementedException(); + } + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() { + throw new System.NotImplementedException(); + } + + #endregion + } + + + + /// + /// An implementation of the + /// + /// interface with a as the backing store. + /// + class FunctionalHashtable : IFunctionalMap { + private readonly Hashtable/*!*/ h; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(h != null); + } + + + /// + /// Cannot directly construct an instance of a FunctionalHashtbl. + /// + private FunctionalHashtable() { + this.h = new Hashtable(); + // base(); + } + + /// + /// Cannot directly construct an instance of a FunctionalHashtbl. + /// + private FunctionalHashtable(Hashtable/*!*/ h) { + Contract.Requires(h != null); + this.h = h; + // base(); + } + + private static readonly IFunctionalMap/*!*/ empty = new FunctionalHashtable(); + public static IFunctionalMap/*!*/ Empty { + get { + Contract.Ensures(Contract.Result() != null); + return empty; + } + } + + public IFunctionalMap/*!*/ Add(object/*!*/ key, object value) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + Hashtable r = h.Clone() as Hashtable; + Contract.Assume(r != null); + r.Add(key, value); + return new FunctionalHashtable(r); + } + + public IFunctionalMap/*!*/ Set(object/*!*/ key, object value) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + Hashtable r = h.Clone() as Hashtable; + + Contract.Assume(r != null); + Contract.Assert(this.Contains(key)); // The entry must be defined + + r[key] = value; + return new FunctionalHashtable(r); + } + + [Pure] + public bool Contains(object/*!*/ key) { + //Contract.Requires(key != null); + return h.Contains(key); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IEnumerator/*!*/ IEnumerable.GetEnumerator() { + Contract.Ensures(Contract.Result() != null); + + return h.GetEnumerator(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IDictionaryEnumerator IFunctionalMap.GetEnumerator() { + return h.GetEnumerator(); + } + + public ICollection Keys { + get { + return h.Keys; + } + } + + public IFunctionalMap/*!*/ Remove(object/*!*/ key) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result() != null); + Hashtable r = h.Clone() as Hashtable; + Contract.Assume(r != null); + r.Remove(key); + return new FunctionalHashtable(r); + } + + public ICollection Values { + get { + return h.Values; + } + } + + + public object this[object/*!*/ key] { + get { + //Contract.Requires(key != null); + return h[key]; + } + } + + public int Count { + [Pure] + get { + return h.Count; + } + } + + public bool IsSynchronized { + [Pure] + get { + return h.IsSynchronized; + } + } + + public object/*!*/ SyncRoot { + [Pure] + get { + Contract.Ensures(Contract.Result() != null); + return h.SyncRoot; + } + } + + public void CopyTo(System.Array/*!*/ a, int index) { + //Contract.Requires(a != null); + h.CopyTo(a, index); + } + } + + public struct Pair/**/ + { + private object first; + private object second; + + public object First { + get { + return first; + } + } + public object Second { + get { + return second; + } + } + + public Pair(object first, object second) { + this.first = first; + this.second = second; + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is Pair)) + return false; + + Pair other = (Pair)obj; + return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); + } + + public override int GetHashCode() { + int h = this.first == null ? 0 : this.first.GetHashCode(); + h ^= this.second == null ? 0 : this.second.GetHashCode(); + return h; + } + } +} + + +namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { + using System.Collections.Generic; + + public struct Pair { + private T1 first; + private T2 second; + + public T1 First { + get { + return first; + } + } + public T2 Second { + get { + return second; + } + } + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is Pair)) + return false; + + Pair other = (Pair)obj; + return object.Equals(this.first, other.first) && object.Equals(this.second, other.second); + } + + public override int GetHashCode() { + int h = this.first == null ? 0 : this.first.GetHashCode(); + h ^= this.second == null ? 0 : this.second.GetHashCode(); + return h; + } + + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format("({0},{1})", first, second); + } + } + + public struct Triple { + private T1 first; + private T2 second; + private T3 third; + + public T1 First { + get { + return first; + } + } + public T2 Second { + get { + return second; + } + } + public T3 Third { + get { + return third; + } + } + + public Triple(T1 first, T2 second, T3 third) { + this.first = first; + this.second = second; + this.third = third; + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is Triple)) + return false; + + Triple other = (Triple)obj; + return object.Equals(this.first, other.first) && object.Equals(this.second, other.second) && object.Equals(this.third, other.third); + } + + public override int GetHashCode() { + int h = this.first == null ? 0 : this.first.GetHashCode(); + h ^= this.second == null ? 0 : this.second.GetHashCode(); + h ^= this.third == null ? 0 : this.third.GetHashCode(); + return h; + } + + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format("({0},{1},{2})", first, second, third); + } + } +} diff --git a/Source/AIFramework/Lattice.cs b/Source/AIFramework/Lattice.cs index ab10be9a..1796f1f6 100644 --- a/Source/AIFramework/Lattice.cs +++ b/Source/AIFramework/Lattice.cs @@ -1,960 +1,960 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System; - using System.Diagnostics.Contracts; - using System.Collections; - using G = System.Collections.Generic; - using System.Diagnostics; - using Microsoft.AbstractInterpretationFramework.Collections; - using Microsoft.Boogie; - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Diagnostics.Contracts; + using System.Collections; + using G = System.Collections.Generic; + using System.Diagnostics; + using Microsoft.AbstractInterpretationFramework.Collections; + using Microsoft.Boogie; + using ArraySet = Microsoft.Boogie.GSet; - using IMutableSet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - using Set = Microsoft.Boogie.GSet; - - - /// - /// Specifies the operations (e.g., join) on a mathematical lattice that depend - /// only on the elements of the lattice. - /// - [ContractClass(typeof(MathematicalLatticeContracts))] - public abstract class MathematicalLattice { - #region Element - /// - /// An element of the lattice. This class should be derived from in any - /// implementation of MathematicalLattice. - /// - [ContractClass(typeof(ElementContracts))] - public abstract class Element : System.ICloneable { - /// - /// Print out a debug-useful representation of the internal data structure of the lattice element. - /// - public virtual void Dump(string/*!*/ msg) { - Contract.Requires(msg != null); - System.Console.WriteLine("Dump({0}) = {1}", msg, this); - } - - public abstract Element/*!*/ Clone(); - object/*!*/ System.ICloneable.Clone() { - return this.Clone(); - } - - public abstract G.ICollection/*!*/ FreeVariables(); - - } - [ContractClassFor(typeof(Element))] - public abstract class ElementContracts : Element { - public override Element Clone() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - - } - - public override System.Collections.Generic.ICollection FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - throw new System.NotImplementedException(); - } - } - #endregion - - public abstract Element/*!*/ Top { - get; - } - public abstract Element/*!*/ Bottom { - get; - } - - public abstract bool IsTop(Element/*!*/ e); - public abstract bool IsBottom(Element/*!*/ e); - - /// - /// Returns true if a <= this. - /// - protected abstract bool AtMost(Element/*!*/ a, Element/*!*/ b); - /* The following cases are handled elsewhere and need not be considered in subclass. */ - // requires a.GetType() == b.GetType(); - // requires ! a.IsTop; - // requires ! a.IsBottom; - // requires ! b.IsTop; - // requires ! b.IsBottom; - - - protected Answer TrivialLowerThan(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - if (a.GetType() != b.GetType()) { - throw new System.InvalidOperationException( - "operands to <= must be of same Element type" - ); - } - if (IsBottom(a)) { - return Answer.Yes; - } - if (IsTop(b)) { - return Answer.Yes; - } - if (IsTop(a)) { - return Answer.No; - } - if (IsBottom(b)) { - return Answer.No; - } - - return Answer.Maybe; - } - - // Is 'a' better information than 'b'? - // - public bool LowerThan(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Answer ans = TrivialLowerThan(a, b); - return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, b); - } - - // Is 'a' worse information than 'b'? - // - public bool HigherThan(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - return LowerThan(b, a); - } - - // Are 'a' and 'b' equivalent? - // - public bool Equivalent(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - return LowerThan(a, b) && LowerThan(b, a); - } - - public abstract Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b); - /* The following cases are handled elsewhere and need not be considered in subclass. */ - // requires a.GetType() == b.GetType(); - // requires ! a.IsTop; - // requires ! a.IsBottom; - // requires ! b.IsTop; - // requires ! b.IsBottom; - - - protected Element/*?*/ TrivialJoin(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - if (a.GetType() != b.GetType()) { - throw new System.InvalidOperationException( - "operands to Join must be of same Lattice.Element type" - ); - } - if (IsTop(a)) { - return a; - } - if (IsTop(b)) { - return b; - } - if (IsBottom(a)) { - return b; - } - if (IsBottom(b)) { - return a; - } - - return null; - } - - public Element/*!*/ Join(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - Element/*?*/ r = TrivialJoin(a, b); - return r != null ? r : NontrivialJoin(a, b); - } - - public abstract Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) - /* The following cases are handled elsewhere and need not be considered in subclass. */ - // requires a.GetType() == b.GetType(); - // requires ! a.IsTop; - // requires ! a.IsBottom; - // requires ! b.IsTop; - // requires ! b.IsBottom; - ; - - protected Element/*?*/ TrivialMeet(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - if (a.GetType() != b.GetType()) { - throw new System.InvalidOperationException( - "operands to Meet must be of same Lattice.Element type" - ); - } - if (IsTop(a)) { - return b; - } - if (IsTop(b)) { - return a; - } - if (IsBottom(a)) { - return a; - } - if (IsBottom(b)) { - return b; - } - - return null; - } - - public Element/*!*/ Meet(Element/*!*/ a, Element/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - Element/*?*/ r = TrivialMeet(a, b); - return r != null ? r : NontrivialMeet(a, b); - } - - public abstract Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b); - - public virtual void Validate() { - Debug.Assert(IsTop(Top)); - Debug.Assert(IsBottom(Bottom)); - Debug.Assert(!IsBottom(Top)); - Debug.Assert(!IsTop(Bottom)); - - Debug.Assert(LowerThan(Top, Top)); - Debug.Assert(LowerThan(Bottom, Top)); - Debug.Assert(LowerThan(Bottom, Bottom)); - - Debug.Assert(IsTop(Join(Top, Top))); - Debug.Assert(IsBottom(Join(Bottom, Bottom))); - } - } - [ContractClassFor(typeof(MathematicalLattice))] - public abstract class MathematicalLatticeContracts : MathematicalLattice { - public override MathematicalLattice.Element Top { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - public override MathematicalLattice.Element Bottom { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - public override bool IsTop(MathematicalLattice.Element e) { - Contract.Requires(e != null); - throw new NotImplementedException(); - } - - public override bool IsBottom(MathematicalLattice.Element e) { - Contract.Requires(e != null); - throw new NotImplementedException(); - } - - protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - throw new NotImplementedException(); - } - - public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - - /// - /// Provides an abstract interface for the operations of a lattice specific - /// to abstract interpretation (i.e., that deals with the expression language). - /// - [ContractClass(typeof(LatticeContracts))] - public abstract class Lattice : MathematicalLattice { - internal readonly IValueExprFactory/*!*/ valueExprFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(valueExprFactory != null); - } - - - public Lattice(IValueExprFactory/*!*/ valueExprFactory) { - Contract.Requires(valueExprFactory != null); - this.valueExprFactory = valueExprFactory; - // base(); - } - - #region Primitives that commands translate into - - public abstract Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable); - - public abstract Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName); - - public abstract Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr); - - #endregion - - - // TODO keep this? - // public Element! Eliminate(Element! e, VariableSeq! variables) - // { - // Lattice.Element result = e; - // foreach (IVariable var in variables) - // { - // result = this.Eliminate(result, var); - // } - // return result; - // } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Note! - // - // Concrete classes that implement Lattice must implement one of the AtMost - // overloads. We provide here a default implementation for one given a "real" - // implementation of the other. Otherwise, there will be an infinite loop! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); - } - - protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); - } - - public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Answer ans = TrivialLowerThan(a, b); - return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, aToResult, b, bToResult); - } - - public bool HigherThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - return LowerThan(b, bToResult, a, aToResult); - } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Note! - // - // Concrete classes that implement Lattice must implement one of the NontrivialJoin - // overloads. We provide here a default implementation for one given a "real" - // implementation of the other. Otherwise, there will be an infinite loop! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); - } - - public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); - } - - public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - Element/*?*/ r = TrivialJoin(a, b); - return r != null ? r : NontrivialJoin(a, aToResult, b, bToResult); - } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Note! - // - // Concrete classes that implement Lattice must implement one of the Widen - // overloads. We provide here a default implementation for one given a "real" - // implementation of the other. Otherwise, there will be an infinite loop! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); - } - - public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - Contract.Requires(bToResult != null); - Contract.Requires(b != null); - Contract.Requires(aToResult != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); - } - - - - /// - /// A default implementation of the given - /// the appropriate expression factories by calling CheckPredicate. - /// - protected Answer DefaultCheckVariableDisequality(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valExprFactory, Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - Contract.Requires(propExprFactory != null); - Contract.Requires(valExprFactory != null); - Contract.Requires(e != null); - Contract.Requires(var1 != null); - Contract.Requires(var2 != null); - return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2))); - } - - private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) { - Contract.Requires(eToResult != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - Element/*!*/ result = e; - - foreach (G.KeyValuePair*//*!*/> entry in eToResult.GetSourceToResult()) { - IVariable/*!*/ sourceName = entry.Key; - Contract.Assert(sourceName != null); - ISet/**//*!*/>/*!*/ emptyDictionary1 = new G.Dictionary*//*!*/>(); - private static readonly G.Dictionary/*!*/ emptyDictionary2 = new G.Dictionary(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Map != null); - Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null)); - Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2)); - Contract.Invariant(indexMap != null); - Contract.Invariant(reverseIndexMap != null); - - } - - - public ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname) { - //Contract.Requires(srcname != null); - ArraySet a = new ArraySet(); - a.Add(srcname); - return a; - } - - public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) { - //Contract.Requires(resname != null); - return resname; - } - - //TODO: uncomment when works in compiler - //public G.IEnumerable*/!>> GetSourceToResult() - public IEnumerable/*!*/ GetSourceToResult() { - Contract.Ensures(Contract.Result() != null); - return emptyDictionary1; - } - - //public G.IEnumerable> GetResultToSource() - public IEnumerable/*!*/ GetResultToSource() { - Contract.Ensures(Contract.Result() != null); - return emptyDictionary2; - } - - private IdentityCombineNameMap() { - } - } - - #region Support for MultiLattice to uniquely number every subclass of Lattice - - - private static Hashtable/**//*!*/ indexMap = new Hashtable(); - private static Hashtable/**//*!*/ reverseIndexMap = new Hashtable(); - private static int globalCount = 0; - - protected virtual object/*!*/ UniqueId { - get { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(this.GetType()); - } - } - - public int Index { - get { - object unique = this.UniqueId; - if (indexMap.ContainsKey(unique)) { - object index = indexMap[unique]; - Contract.Assert(index != null); // this does nothing for nonnull analysis - if (index != null) { - return (int)index; - } - return 0; - } else { - int myIndex = globalCount++; - indexMap[unique] = myIndex; - reverseIndexMap[myIndex] = this; - return myIndex; - } - } - } - - public static Lattice GetGlobalLattice(int i) { - return reverseIndexMap[i] as Lattice; - } - #endregion - - public static bool LogSwitch = false; - /// - /// Returns the predicate that corresponds to the given lattice element. - /// - public abstract IExpr/*!*/ ToPredicate(Element/*!*/ e); - - /// - /// Allows the lattice to specify whether it understands a particular function symbol. - /// - /// The lattice is always allowed to return "true" even when it really can't do anything - /// with such functions; however, it is advantageous to say "false" when possible to - /// avoid being called to do certain things. - /// - /// The arguments to a function are provided for context so that the lattice can say - /// true or false for the same function symbol in different situations. For example, - /// a lattice may understand the multiplication of a variable and a constant but not - /// of two variables. The implementation of a lattice should not hold on to the - /// arguments. - /// - /// The function symbol. - /// The argument context. - /// True if it may understand f, false if it does not understand f. - public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); - - /// - /// Return an expression that is equivalent to the given expression that does not - /// contain the given variable according to the lattice element and queryable. - /// - /// The lattice element. - /// A queryable for asking addtional information. - /// The expression to find an equivalent expression. - /// The variable to eliminate. - /// The set of variables that can't be used in the resulting expression. - /// - /// An equivalent expression to without - /// or null if not possible. - /// - public abstract IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars); - - /// - /// Answers a query about whether the given predicate holds given the lattice element. - /// - /// The lattice element. - /// The predicate. - /// Yes, No, or Maybe. - public abstract Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred); - - /// - /// Answers a disequality about two variables. The same information could be obtained - /// by asking CheckPredicate, but a different implementation may be simpler and more - /// efficient. - /// - /// The lattice element. - /// The first variable. - /// The second variable. - /// Yes, No, or Maybe. - public abstract Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2); - - public abstract string/*!*/ ToString(Element/*!*/ e); // for debugging - - } - [ContractClassFor(typeof(Lattice))] - abstract class LatticeContracts : Lattice { - public LatticeContracts() - : base(null) { - } - public override IExpr ToPredicate(MathematicalLattice.Element e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override bool Understands(IFunctionSymbol f, IList args) { - Contract.Requires(f != null); - Contract.Requires(args != null); - throw new NotImplementedException(); - } - public override IExpr EquivalentExpr(MathematicalLattice.Element e, IQueryable q, IExpr expr, IVariable var, Set prohibitedVars) { - Contract.Requires(e != null); - Contract.Requires(q != null); - Contract.Requires(expr != null); - Contract.Requires(var != null); - Contract.Requires(prohibitedVars != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override Answer CheckPredicate(MathematicalLattice.Element e, IExpr pred) { - Contract.Requires(e != null); - Contract.Requires(pred != null); - throw new NotImplementedException(); - } - public override Answer CheckVariableDisequality(MathematicalLattice.Element e, IVariable var1, IVariable var2) { - Contract.Requires(e != null); - Contract.Requires(var1 != null); - Contract.Requires(var2 != null); - throw new NotImplementedException(); - } - public override string ToString(Element e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override MathematicalLattice.Element Eliminate(MathematicalLattice.Element e, IVariable variable) { - Contract.Requires(e != null); - Contract.Requires(variable != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override MathematicalLattice.Element Rename(MathematicalLattice.Element e, IVariable oldName, IVariable newName) { - Contract.Requires(e != null); - Contract.Requires(oldName != null); - Contract.Requires(newName != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - public override MathematicalLattice.Element Constrain(MathematicalLattice.Element e, IExpr expr) { - Contract.Requires(e != null); - Contract.Requires(expr != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - /// - /// Defines the relation between names used in the respective input lattice elements to the - /// various combination operators (Join,Widen,Meet,AtMost) and the names that should be used - /// in the resulting lattice element. - /// - [ContractClass(typeof(ICombineNameMapContracts))] - public interface ICombineNameMap { - ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname); - IVariable/*?*/ GetSourceName(IVariable/*!*/ resname); - - //TODO: uncommet when works in compiler - //G.IEnumerable*/!>> GetSourceToResult(); - IEnumerable/*!*/ GetSourceToResult(); - //G.IEnumerable> GetResultToSource(); - IEnumerable/*!*/ GetResultToSource(); - } - [ContractClassFor(typeof(ICombineNameMap))] - public abstract class ICombineNameMapContracts : ICombineNameMap { - #region ICombineNameMap Members - - public Set GetResultNames(IVariable srcname) { - Contract.Requires(srcname != null); - throw new NotImplementedException(); - } - - public IVariable GetSourceName(IVariable resname) { - Contract.Requires(resname != null); - throw new NotImplementedException(); - } - - public IEnumerable GetSourceToResult() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public IEnumerable GetResultToSource() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - #endregion - } - - /// - /// Provides statistics on the number of times an operation is performed - /// and forwards the real operations to the given lattice in the constructor. - /// - public class StatisticsLattice : Lattice { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lattice != null); - } - - readonly Lattice/*!*/ lattice; - int eliminateCount; - int renameCount; - int constrainCount; - int toPredicateCount; - int atMostCount; - int topCount; - int bottomCount; - int isTopCount; - int isBottomCount; - int joinCount; - int meetCount; - int widenCount; - int understandsCount; - int equivalentExprCount; - int checkPredicateCount; - int checkVariableDisequalityCount; - - public StatisticsLattice(Lattice/*!*/ lattice) - : base(lattice.valueExprFactory) { - Contract.Requires(lattice != null); - this.lattice = lattice; - // base(lattice.valueExprFactory); - } - - public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - eliminateCount++; - return lattice.Eliminate(e, variable); - } - - public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - renameCount++; - return lattice.Rename(e, oldName, newName); - } - - public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - constrainCount++; - return lattice.Constrain(e, expr); - } - - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - understandsCount++; - return lattice.Understands(f, args); - } - - - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(e != null); - equivalentExprCount++; - return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars); - } - - - public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(e != null); - checkPredicateCount++; - return lattice.CheckPredicate(e, pred); - } - - - public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(e != null); - checkVariableDisequalityCount++; - return lattice.CheckVariableDisequality(e, var1, var2); - } - - - - public override IExpr/*!*/ ToPredicate(Element/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - toPredicateCount++; - return lattice.ToPredicate(e); - } - - public override string/*!*/ ToString(Element/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - return lattice.ToString(e); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return string.Format( - "StatisticsLattice: #Eliminate={0} #Rename={1} #Constrain={2} #ToPredicate={3} " + - "#Understands={4} #EquivalentExpr={5} #CheckPredicate={6} #CheckVariableDisequality={7} " + - "#AtMost={8} #Top={9} #Bottom={9} #IsTop={10} #IsBottom={11} " + - "#NonTrivialJoin={12} #NonTrivialMeet={13} #Widen={14}", - eliminateCount, renameCount, constrainCount, toPredicateCount, - understandsCount, equivalentExprCount, checkPredicateCount, checkVariableDisequalityCount, - atMostCount, topCount, bottomCount, isTopCount, isBottomCount, - joinCount, meetCount, widenCount); - } - - protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - atMostCount++; - return lattice.LowerThan(a, b); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - topCount++; - return lattice.Top; - } - } - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - bottomCount++; - return lattice.Bottom; - } - } - - public override bool IsTop(Element/*!*/ e) { - //Contract.Requires(e != null); - isTopCount++; - return lattice.IsTop(e); - } - - public override bool IsBottom(Element/*!*/ e) { - //Contract.Requires(e != null); - isBottomCount++; - return lattice.IsBottom(e); - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - joinCount++; - return lattice.NontrivialJoin(a, b); - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - meetCount++; - return lattice.NontrivialMeet(a, b); - } - - public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires(b != null); - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - widenCount++; - return lattice.Widen(a, b); - } - - public override void Validate() { - base.Validate(); - lattice.Validate(); - } - - protected override object/*!*/ UniqueId { - get { - Contract.Ensures(Contract.Result() != null); - // use the base id, not the underlying-lattice id (is that the right thing to do?) - return base.UniqueId; - } - } - } - - - public sealed class LatticeQueryable : IQueryable { - private Lattice/*!*/ lattice; - private Lattice.Element/*!*/ element; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lattice != null); - Contract.Invariant(element != null); - } - - - public LatticeQueryable(Lattice/*!*/ lattice, Lattice.Element/*!*/ element) { - Contract.Requires(element != null); - Contract.Requires(lattice != null); - this.lattice = lattice; - this.element = element; - // base(); - } - - public Answer CheckPredicate(IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - return lattice.CheckPredicate(element, pred); - } - - public Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - return lattice.CheckVariableDisequality(element, var1, var2); - } - } -} + using IMutableSet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + using Set = Microsoft.Boogie.GSet; + + + /// + /// Specifies the operations (e.g., join) on a mathematical lattice that depend + /// only on the elements of the lattice. + /// + [ContractClass(typeof(MathematicalLatticeContracts))] + public abstract class MathematicalLattice { + #region Element + /// + /// An element of the lattice. This class should be derived from in any + /// implementation of MathematicalLattice. + /// + [ContractClass(typeof(ElementContracts))] + public abstract class Element : System.ICloneable { + /// + /// Print out a debug-useful representation of the internal data structure of the lattice element. + /// + public virtual void Dump(string/*!*/ msg) { + Contract.Requires(msg != null); + System.Console.WriteLine("Dump({0}) = {1}", msg, this); + } + + public abstract Element/*!*/ Clone(); + object/*!*/ System.ICloneable.Clone() { + return this.Clone(); + } + + public abstract G.ICollection/*!*/ FreeVariables(); + + } + [ContractClassFor(typeof(Element))] + public abstract class ElementContracts : Element { + public override Element Clone() { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + + } + + public override System.Collections.Generic.ICollection FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + throw new System.NotImplementedException(); + } + } + #endregion + + public abstract Element/*!*/ Top { + get; + } + public abstract Element/*!*/ Bottom { + get; + } + + public abstract bool IsTop(Element/*!*/ e); + public abstract bool IsBottom(Element/*!*/ e); + + /// + /// Returns true if a <= this. + /// + protected abstract bool AtMost(Element/*!*/ a, Element/*!*/ b); + /* The following cases are handled elsewhere and need not be considered in subclass. */ + // requires a.GetType() == b.GetType(); + // requires ! a.IsTop; + // requires ! a.IsBottom; + // requires ! b.IsTop; + // requires ! b.IsBottom; + + + protected Answer TrivialLowerThan(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + if (a.GetType() != b.GetType()) { + throw new System.InvalidOperationException( + "operands to <= must be of same Element type" + ); + } + if (IsBottom(a)) { + return Answer.Yes; + } + if (IsTop(b)) { + return Answer.Yes; + } + if (IsTop(a)) { + return Answer.No; + } + if (IsBottom(b)) { + return Answer.No; + } + + return Answer.Maybe; + } + + // Is 'a' better information than 'b'? + // + public bool LowerThan(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Answer ans = TrivialLowerThan(a, b); + return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, b); + } + + // Is 'a' worse information than 'b'? + // + public bool HigherThan(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + return LowerThan(b, a); + } + + // Are 'a' and 'b' equivalent? + // + public bool Equivalent(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + return LowerThan(a, b) && LowerThan(b, a); + } + + public abstract Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b); + /* The following cases are handled elsewhere and need not be considered in subclass. */ + // requires a.GetType() == b.GetType(); + // requires ! a.IsTop; + // requires ! a.IsBottom; + // requires ! b.IsTop; + // requires ! b.IsBottom; + + + protected Element/*?*/ TrivialJoin(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + if (a.GetType() != b.GetType()) { + throw new System.InvalidOperationException( + "operands to Join must be of same Lattice.Element type" + ); + } + if (IsTop(a)) { + return a; + } + if (IsTop(b)) { + return b; + } + if (IsBottom(a)) { + return b; + } + if (IsBottom(b)) { + return a; + } + + return null; + } + + public Element/*!*/ Join(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + Element/*?*/ r = TrivialJoin(a, b); + return r != null ? r : NontrivialJoin(a, b); + } + + public abstract Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) + /* The following cases are handled elsewhere and need not be considered in subclass. */ + // requires a.GetType() == b.GetType(); + // requires ! a.IsTop; + // requires ! a.IsBottom; + // requires ! b.IsTop; + // requires ! b.IsBottom; + ; + + protected Element/*?*/ TrivialMeet(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + if (a.GetType() != b.GetType()) { + throw new System.InvalidOperationException( + "operands to Meet must be of same Lattice.Element type" + ); + } + if (IsTop(a)) { + return b; + } + if (IsTop(b)) { + return a; + } + if (IsBottom(a)) { + return a; + } + if (IsBottom(b)) { + return b; + } + + return null; + } + + public Element/*!*/ Meet(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + Element/*?*/ r = TrivialMeet(a, b); + return r != null ? r : NontrivialMeet(a, b); + } + + public abstract Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b); + + public virtual void Validate() { + Debug.Assert(IsTop(Top)); + Debug.Assert(IsBottom(Bottom)); + Debug.Assert(!IsBottom(Top)); + Debug.Assert(!IsTop(Bottom)); + + Debug.Assert(LowerThan(Top, Top)); + Debug.Assert(LowerThan(Bottom, Top)); + Debug.Assert(LowerThan(Bottom, Bottom)); + + Debug.Assert(IsTop(Join(Top, Top))); + Debug.Assert(IsBottom(Join(Bottom, Bottom))); + } + } + [ContractClassFor(typeof(MathematicalLattice))] + public abstract class MathematicalLatticeContracts : MathematicalLattice { + public override MathematicalLattice.Element Top { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + public override MathematicalLattice.Element Bottom { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + public override bool IsTop(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new NotImplementedException(); + } + + public override bool IsBottom(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new NotImplementedException(); + } + + protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + + /// + /// Provides an abstract interface for the operations of a lattice specific + /// to abstract interpretation (i.e., that deals with the expression language). + /// + [ContractClass(typeof(LatticeContracts))] + public abstract class Lattice : MathematicalLattice { + internal readonly IValueExprFactory/*!*/ valueExprFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(valueExprFactory != null); + } + + + public Lattice(IValueExprFactory/*!*/ valueExprFactory) { + Contract.Requires(valueExprFactory != null); + this.valueExprFactory = valueExprFactory; + // base(); + } + + #region Primitives that commands translate into + + public abstract Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable); + + public abstract Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName); + + public abstract Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr); + + #endregion + + + // TODO keep this? + // public Element! Eliminate(Element! e, VariableSeq! variables) + // { + // Lattice.Element result = e; + // foreach (IVariable var in variables) + // { + // result = this.Eliminate(result, var); + // } + // return result; + // } + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Note! + // + // Concrete classes that implement Lattice must implement one of the AtMost + // overloads. We provide here a default implementation for one given a "real" + // implementation of the other. Otherwise, there will be an infinite loop! + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Answer ans = TrivialLowerThan(a, b); + return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, aToResult, b, bToResult); + } + + public bool HigherThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + return LowerThan(b, bToResult, a, aToResult); + } + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Note! + // + // Concrete classes that implement Lattice must implement one of the NontrivialJoin + // overloads. We provide here a default implementation for one given a "real" + // implementation of the other. Otherwise, there will be an infinite loop! + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + Element/*?*/ r = TrivialJoin(a, b); + return r != null ? r : NontrivialJoin(a, aToResult, b, bToResult); + } + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Note! + // + // Concrete classes that implement Lattice must implement one of the Widen + // overloads. We provide here a default implementation for one given a "real" + // implementation of the other. Otherwise, there will be an infinite loop! + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + + + /// + /// A default implementation of the given + /// the appropriate expression factories by calling CheckPredicate. + /// + protected Answer DefaultCheckVariableDisequality(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valExprFactory, Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + Contract.Requires(propExprFactory != null); + Contract.Requires(valExprFactory != null); + Contract.Requires(e != null); + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2))); + } + + private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) { + Contract.Requires(eToResult != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + Element/*!*/ result = e; + + foreach (G.KeyValuePair*//*!*/> entry in eToResult.GetSourceToResult()) { + IVariable/*!*/ sourceName = entry.Key; + Contract.Assert(sourceName != null); + ISet/**//*!*/>/*!*/ emptyDictionary1 = new G.Dictionary*//*!*/>(); + private static readonly G.Dictionary/*!*/ emptyDictionary2 = new G.Dictionary(); + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Map != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null)); + Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2)); + Contract.Invariant(indexMap != null); + Contract.Invariant(reverseIndexMap != null); + + } + + + public ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname) { + //Contract.Requires(srcname != null); + ArraySet a = new ArraySet(); + a.Add(srcname); + return a; + } + + public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) { + //Contract.Requires(resname != null); + return resname; + } + + //TODO: uncomment when works in compiler + //public G.IEnumerable*/!>> GetSourceToResult() + public IEnumerable/*!*/ GetSourceToResult() { + Contract.Ensures(Contract.Result() != null); + return emptyDictionary1; + } + + //public G.IEnumerable> GetResultToSource() + public IEnumerable/*!*/ GetResultToSource() { + Contract.Ensures(Contract.Result() != null); + return emptyDictionary2; + } + + private IdentityCombineNameMap() { + } + } + + #region Support for MultiLattice to uniquely number every subclass of Lattice + + + private static Hashtable/**//*!*/ indexMap = new Hashtable(); + private static Hashtable/**//*!*/ reverseIndexMap = new Hashtable(); + private static int globalCount = 0; + + protected virtual object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(this.GetType()); + } + } + + public int Index { + get { + object unique = this.UniqueId; + if (indexMap.ContainsKey(unique)) { + object index = indexMap[unique]; + Contract.Assert(index != null); // this does nothing for nonnull analysis + if (index != null) { + return (int)index; + } + return 0; + } else { + int myIndex = globalCount++; + indexMap[unique] = myIndex; + reverseIndexMap[myIndex] = this; + return myIndex; + } + } + } + + public static Lattice GetGlobalLattice(int i) { + return reverseIndexMap[i] as Lattice; + } + #endregion + + public static bool LogSwitch = false; + /// + /// Returns the predicate that corresponds to the given lattice element. + /// + public abstract IExpr/*!*/ ToPredicate(Element/*!*/ e); + + /// + /// Allows the lattice to specify whether it understands a particular function symbol. + /// + /// The lattice is always allowed to return "true" even when it really can't do anything + /// with such functions; however, it is advantageous to say "false" when possible to + /// avoid being called to do certain things. + /// + /// The arguments to a function are provided for context so that the lattice can say + /// true or false for the same function symbol in different situations. For example, + /// a lattice may understand the multiplication of a variable and a constant but not + /// of two variables. The implementation of a lattice should not hold on to the + /// arguments. + /// + /// The function symbol. + /// The argument context. + /// True if it may understand f, false if it does not understand f. + public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); + + /// + /// Return an expression that is equivalent to the given expression that does not + /// contain the given variable according to the lattice element and queryable. + /// + /// The lattice element. + /// A queryable for asking addtional information. + /// The expression to find an equivalent expression. + /// The variable to eliminate. + /// The set of variables that can't be used in the resulting expression. + /// + /// An equivalent expression to without + /// or null if not possible. + /// + public abstract IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars); + + /// + /// Answers a query about whether the given predicate holds given the lattice element. + /// + /// The lattice element. + /// The predicate. + /// Yes, No, or Maybe. + public abstract Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred); + + /// + /// Answers a disequality about two variables. The same information could be obtained + /// by asking CheckPredicate, but a different implementation may be simpler and more + /// efficient. + /// + /// The lattice element. + /// The first variable. + /// The second variable. + /// Yes, No, or Maybe. + public abstract Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2); + + public abstract string/*!*/ ToString(Element/*!*/ e); // for debugging + + } + [ContractClassFor(typeof(Lattice))] + abstract class LatticeContracts : Lattice { + public LatticeContracts() + : base(null) { + } + public override IExpr ToPredicate(MathematicalLattice.Element e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override bool Understands(IFunctionSymbol f, IList args) { + Contract.Requires(f != null); + Contract.Requires(args != null); + throw new NotImplementedException(); + } + public override IExpr EquivalentExpr(MathematicalLattice.Element e, IQueryable q, IExpr expr, IVariable var, Set prohibitedVars) { + Contract.Requires(e != null); + Contract.Requires(q != null); + Contract.Requires(expr != null); + Contract.Requires(var != null); + Contract.Requires(prohibitedVars != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override Answer CheckPredicate(MathematicalLattice.Element e, IExpr pred) { + Contract.Requires(e != null); + Contract.Requires(pred != null); + throw new NotImplementedException(); + } + public override Answer CheckVariableDisequality(MathematicalLattice.Element e, IVariable var1, IVariable var2) { + Contract.Requires(e != null); + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + throw new NotImplementedException(); + } + public override string ToString(Element e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Eliminate(MathematicalLattice.Element e, IVariable variable) { + Contract.Requires(e != null); + Contract.Requires(variable != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Rename(MathematicalLattice.Element e, IVariable oldName, IVariable newName) { + Contract.Requires(e != null); + Contract.Requires(oldName != null); + Contract.Requires(newName != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Constrain(MathematicalLattice.Element e, IExpr expr) { + Contract.Requires(e != null); + Contract.Requires(expr != null); + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + /// + /// Defines the relation between names used in the respective input lattice elements to the + /// various combination operators (Join,Widen,Meet,AtMost) and the names that should be used + /// in the resulting lattice element. + /// + [ContractClass(typeof(ICombineNameMapContracts))] + public interface ICombineNameMap { + ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname); + IVariable/*?*/ GetSourceName(IVariable/*!*/ resname); + + //TODO: uncommet when works in compiler + //G.IEnumerable*/!>> GetSourceToResult(); + IEnumerable/*!*/ GetSourceToResult(); + //G.IEnumerable> GetResultToSource(); + IEnumerable/*!*/ GetResultToSource(); + } + [ContractClassFor(typeof(ICombineNameMap))] + public abstract class ICombineNameMapContracts : ICombineNameMap { + #region ICombineNameMap Members + + public Set GetResultNames(IVariable srcname) { + Contract.Requires(srcname != null); + throw new NotImplementedException(); + } + + public IVariable GetSourceName(IVariable resname) { + Contract.Requires(resname != null); + throw new NotImplementedException(); + } + + public IEnumerable GetSourceToResult() { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + public IEnumerable GetResultToSource() { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + #endregion + } + + /// + /// Provides statistics on the number of times an operation is performed + /// and forwards the real operations to the given lattice in the constructor. + /// + public class StatisticsLattice : Lattice { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattice != null); + } + + readonly Lattice/*!*/ lattice; + int eliminateCount; + int renameCount; + int constrainCount; + int toPredicateCount; + int atMostCount; + int topCount; + int bottomCount; + int isTopCount; + int isBottomCount; + int joinCount; + int meetCount; + int widenCount; + int understandsCount; + int equivalentExprCount; + int checkPredicateCount; + int checkVariableDisequalityCount; + + public StatisticsLattice(Lattice/*!*/ lattice) + : base(lattice.valueExprFactory) { + Contract.Requires(lattice != null); + this.lattice = lattice; + // base(lattice.valueExprFactory); + } + + public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + eliminateCount++; + return lattice.Eliminate(e, variable); + } + + public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + renameCount++; + return lattice.Rename(e, oldName, newName); + } + + public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + constrainCount++; + return lattice.Constrain(e, expr); + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + understandsCount++; + return lattice.Understands(f, args); + } + + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + equivalentExprCount++; + return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars); + } + + + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + checkPredicateCount++; + return lattice.CheckPredicate(e, pred); + } + + + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + checkVariableDisequalityCount++; + return lattice.CheckVariableDisequality(e, var1, var2); + } + + + + public override IExpr/*!*/ ToPredicate(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + toPredicateCount++; + return lattice.ToPredicate(e); + } + + public override string/*!*/ ToString(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + return lattice.ToString(e); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return string.Format( + "StatisticsLattice: #Eliminate={0} #Rename={1} #Constrain={2} #ToPredicate={3} " + + "#Understands={4} #EquivalentExpr={5} #CheckPredicate={6} #CheckVariableDisequality={7} " + + "#AtMost={8} #Top={9} #Bottom={9} #IsTop={10} #IsBottom={11} " + + "#NonTrivialJoin={12} #NonTrivialMeet={13} #Widen={14}", + eliminateCount, renameCount, constrainCount, toPredicateCount, + understandsCount, equivalentExprCount, checkPredicateCount, checkVariableDisequalityCount, + atMostCount, topCount, bottomCount, isTopCount, isBottomCount, + joinCount, meetCount, widenCount); + } + + protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + atMostCount++; + return lattice.LowerThan(a, b); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + topCount++; + return lattice.Top; + } + } + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + bottomCount++; + return lattice.Bottom; + } + } + + public override bool IsTop(Element/*!*/ e) { + //Contract.Requires(e != null); + isTopCount++; + return lattice.IsTop(e); + } + + public override bool IsBottom(Element/*!*/ e) { + //Contract.Requires(e != null); + isBottomCount++; + return lattice.IsBottom(e); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + joinCount++; + return lattice.NontrivialJoin(a, b); + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + meetCount++; + return lattice.NontrivialMeet(a, b); + } + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + widenCount++; + return lattice.Widen(a, b); + } + + public override void Validate() { + base.Validate(); + lattice.Validate(); + } + + protected override object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result() != null); + // use the base id, not the underlying-lattice id (is that the right thing to do?) + return base.UniqueId; + } + } + } + + + public sealed class LatticeQueryable : IQueryable { + private Lattice/*!*/ lattice; + private Lattice.Element/*!*/ element; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattice != null); + Contract.Invariant(element != null); + } + + + public LatticeQueryable(Lattice/*!*/ lattice, Lattice.Element/*!*/ element) { + Contract.Requires(element != null); + Contract.Requires(lattice != null); + this.lattice = lattice; + this.element = element; + // base(); + } + + public Answer CheckPredicate(IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + return lattice.CheckPredicate(element, pred); + } + + public Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + return lattice.CheckVariableDisequality(element, var1, var2); + } + } +} diff --git a/Source/AIFramework/Logger.cs b/Source/AIFramework/Logger.cs index aa7c5979..5b455ab0 100644 --- a/Source/AIFramework/Logger.cs +++ b/Source/AIFramework/Logger.cs @@ -1,56 +1,56 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System; - using System.Diagnostics; - using System.Diagnostics.Contracts; - - public class Logger { - private string/*!*/ dbgmsgContext; - private static int contextWidth = 0; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(dbgmsgContext != null); - Contract.Invariant(dbgmsgIndent != null); - } - - - public bool Enabled = false; - - public Logger(string/*!*/ contextMsg) { - Contract.Requires(contextMsg != null); - this.dbgmsgContext = "[" + contextMsg + "] "; - contextWidth = Math.Max(contextWidth, contextMsg.Length + 3); - // base(); - } - - private static System.Text.StringBuilder/*!*/ dbgmsgIndent = new System.Text.StringBuilder(); - - public void DbgMsgIndent() { - dbgmsgIndent.Append(' ', 2); - } - public void DbgMsgUnindent() { - if (dbgmsgIndent.Length >= 2) - dbgmsgIndent.Remove(0, 2); - } - - [ConditionalAttribute("DEBUG")] - public void DbgMsg(string msg) { - if (Enabled) - Debug.WriteLine(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); - } - [ConditionalAttribute("DEBUG")] - public void DbgMsgNoLine(string msg) { - if (Enabled) - Debug.Write(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); - } - [ConditionalAttribute("DEBUG")] - public void DbgMsgPlain(string msg) { - if (Enabled) - Debug.Write(msg); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Diagnostics; + using System.Diagnostics.Contracts; + + public class Logger { + private string/*!*/ dbgmsgContext; + private static int contextWidth = 0; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(dbgmsgContext != null); + Contract.Invariant(dbgmsgIndent != null); + } + + + public bool Enabled = false; + + public Logger(string/*!*/ contextMsg) { + Contract.Requires(contextMsg != null); + this.dbgmsgContext = "[" + contextMsg + "] "; + contextWidth = Math.Max(contextWidth, contextMsg.Length + 3); + // base(); + } + + private static System.Text.StringBuilder/*!*/ dbgmsgIndent = new System.Text.StringBuilder(); + + public void DbgMsgIndent() { + dbgmsgIndent.Append(' ', 2); + } + public void DbgMsgUnindent() { + if (dbgmsgIndent.Length >= 2) + dbgmsgIndent.Remove(0, 2); + } + + [ConditionalAttribute("DEBUG")] + public void DbgMsg(string msg) { + if (Enabled) + Debug.WriteLine(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); + } + [ConditionalAttribute("DEBUG")] + public void DbgMsgNoLine(string msg) { + if (Enabled) + Debug.Write(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg); + } + [ConditionalAttribute("DEBUG")] + public void DbgMsgPlain(string msg) { + if (Enabled) + Debug.Write(msg); + } + } +} diff --git a/Source/AIFramework/MultiLattice.cs b/Source/AIFramework/MultiLattice.cs index ba9aa752..4c9de5f0 100644 --- a/Source/AIFramework/MultiLattice.cs +++ b/Source/AIFramework/MultiLattice.cs @@ -1,647 +1,647 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using Microsoft.AbstractInterpretationFramework.Collections; - - using Microsoft.Boogie; - - using ISet = Microsoft.Boogie.GSet; - using Set = Microsoft.Boogie.GSet; - - - /// - /// The cartesian product lattice. - /// - public class MultiLattice : Lattice, IEnumerable { - internal class Elt : Element { - public /*MaybeNull*/Element[] elementPerLattice; - - public Elt(int domainCount, bool isBottom) { - this.elementPerLattice = (domainCount == 0 && isBottom) ? null : new Element[domainCount]; - } - - private Elt(Elt/*!*/ other) { - Contract.Requires(other != null); - Element[] otherEPL = other.elementPerLattice; - if (otherEPL != null) { - Element[] newEPL = new Element[otherEPL.Length]; - for (int i = 0; i < newEPL.Length; i++) { - newEPL[i] = (Element)(cce.NonNull(otherEPL[i])).Clone(); - } - this.elementPerLattice = newEPL; - } - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new Elt(this); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - // string s = "MultiLattice+Elt{"; - // string sep = ""; - // Element[] epl = this.elementPerLattice; - // if (epl != null) - // { - // foreach (Element! e in epl) - // { - // s += sep + e.ToString(); - // sep = ", "; - // } - // } - // return s + "}"; - if (elementPerLattice == null) - return ""; - System.Text.StringBuilder buffer = new System.Text.StringBuilder(); - for (int i = 0; i < this.Count; i++) { - if (i > 0) - buffer.Append("; "); - buffer.AppendFormat("{0}", elementPerLattice[i]); - } - return buffer.ToString(); - } - - public override void Dump(string/*!*/ msg) { - //Contract.Requires(msg != null); - System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg); - Element[] epl = this.elementPerLattice; - if (epl != null) { - foreach (Element/*!*/ e in epl) { - Contract.Assert(e != null); - e.Dump(msg); - } - } - } - - [Pure] - public override ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - List/*!*/ list = new List(); - for (int i = 0; i < this.Count; i++) { - list.AddRange(cce.NonNull(this[i]).FreeVariables()); - } - return cce.NonNull(list.AsReadOnly()); - } - - public static Elt/*!*/ Top(ArrayList/**//*!*/ lattices) { - Contract.Requires(lattices != null); - Contract.Ensures(Contract.Result() != null); - Elt multiValue = new Elt(lattices.Count, false); - for (int i = 0; i < lattices.Count; i++) { - Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); - multiValue[d.Index] = d.Top; - } - Debug.Assert(multiValue.IsValid); - return multiValue; - } - - - public static Elt/*!*/ Bottom(ArrayList/**//*!*/ lattices) { - Contract.Requires(lattices != null); - Contract.Ensures(Contract.Result() != null); - Elt multiValue = new Elt(lattices.Count, true); - for (int i = 0; i < lattices.Count; i++) { - Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); - multiValue[d.Index] = d.Bottom; - } - Debug.Assert(multiValue.IsValid); - return multiValue; - } - - public bool IsValid { - get { - if (this.elementPerLattice == null) { - return true; /*bottom*/ - } - - Element[] epl = this.elementPerLattice; - for (int i = 0; i < epl.Length; i++) { - if (epl[i] == null) { - return false; - } - } - return true; - } - } - - public int Count { - get { - return this.elementPerLattice == null ? 0 : this.elementPerLattice.Length; - } - } - - public bool Contains(int i) { - return 0 <= i && i < this.Count; - } - - public Element this[int i] // just syntactic sugar - { - get { - Element[] epl = this.elementPerLattice; - return epl == null ? null : epl[i]; - } - set { - Element[] epl = this.elementPerLattice; - if (epl == null) - return; - epl[i] = value; - } - } - - } // class - - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lattices != null); - Contract.Invariant(propExprFactory != null); - } - - ArrayList/**//*!*/ lattices = new ArrayList(); - - private readonly IPropExprFactory/*!*/ propExprFactory; - - - public MultiLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory) - : base(valueExprFactory) { - Contract.Requires(valueExprFactory != null); - Contract.Requires(propExprFactory != null); - this.propExprFactory = propExprFactory; - // base(valueExprFactory); - } - - - - public void AddLattice(Lattice lattice) { - this.lattices.Add(lattice); - } - - private Lattice/*!*/ SubLattice(int i) { - Contract.Ensures(Contract.Result() != null); - return (Lattice/*!*/)cce.NonNull(this.lattices[i]); - } - - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Top(this.lattices); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Bottom(this.lattices); - } - } - - - - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - // The program is errorneous/nonterminating if any subdomain knows it is. - // - if (e.elementPerLattice == null) { - return true; - } - for (int i = 0; i < e.Count; i++) { - if (SubLattice(i).IsBottom(cce.NonNull(e[i]))) { - return true; - } - } - return false; - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - if (e.elementPerLattice == null) { - return false; - } - // The multidomain knows nothing about the program only if no subdomain - // knows anything about it. - // - for (int i = 0; i < e.Count; i++) { - if (!SubLattice(i).IsTop(cce.NonNull(e[i]))) { - return false; - } - } - return true; - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - for (int i = 0; i < a.Count; i++) { - Element thisElement = cce.NonNull(a[i]); - Element thatElement = cce.NonNull(b[i]); - if (thisElement.GetType() != thatElement.GetType()) { - throw new System.InvalidOperationException( - "AtMost called on MultiDomain objects with different lattices" - ); - } - if (!SubLattice(i).LowerThan(thisElement, thatElement)) { - return false; - } - } - return true; - } - - protected override bool AtMost(Element/*!*/ first, ICombineNameMap/*!*/ firstToResult, Element/*!*/ second, ICombineNameMap/*!*/ secondToResult) { - //Contract.Requires(secondToResult != null); - //Contract.Requires(second != null); - //Contract.Requires(firstToResult != null); - //Contract.Requires(first != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - for (int i = 0; i < a.Count; i++) { - Element thisElement = cce.NonNull(a[i]); - Element thatElement = cce.NonNull(b[i]); - if (thisElement.GetType() != thatElement.GetType()) { - throw new System.InvalidOperationException( - "AtMost called on MultiDomain objects with different lattices" - ); - } - if (!SubLattice(i).LowerThan(thisElement, firstToResult, thatElement, secondToResult)) { - return false; - } - } - return true; - } - - - private enum CombineOp { - Meet, - Join, - Widen - } - - private Element/*!*/ Combine(Element/*!*/ first, ICombineNameMap/*?*/ firstToResult, Element/*!*/ second, ICombineNameMap/*?*/ secondToResult, CombineOp c) { - Contract.Requires(second != null); - Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - int unionCount = System.Math.Max(a.Count, b.Count); - Elt combined = new Elt(unionCount, IsBottom(a) && IsBottom(b)); - for (int i = 0; i < unionCount; i++) { - bool thisExists = a.Contains(i); - bool thatExists = b.Contains(i); - - if (thisExists && thatExists) { - Lattice.Element suba = a[i]; - Lattice.Element subb = b[i]; - Contract.Assert(suba != null && subb != null); - - switch (c) { - case CombineOp.Meet: - combined[i] = SubLattice(i).Meet(suba, subb); - break; - case CombineOp.Join: - if (firstToResult != null && secondToResult != null) - combined[i] = SubLattice(i).Join(suba, firstToResult, subb, secondToResult); - else - combined[i] = SubLattice(i).Join(suba, subb); - break; - case CombineOp.Widen: - if (firstToResult != null && secondToResult != null) - combined[i] = SubLattice(i).Widen(suba, firstToResult, subb, secondToResult); - else - combined[i] = SubLattice(i).Widen(suba, subb); - break; - } - } else if (thisExists) { - combined[i] = a[i]; - } else { - combined[i] = b[i]; - } - } - Debug.Assert(combined.IsValid); - return combined; - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires((b != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, null, b, null, CombineOp.Join); - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - //Contract.Requires((bToResult != null)); - //Contract.Requires((b != null)); - //Contract.Requires((aToResult != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, aToResult, b, bToResult, CombineOp.Join); - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires((b != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, null, b, null, CombineOp.Meet); - } - - public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { - //Contract.Requires((b != null)); - //Contract.Requires((a != null)); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, null, b, null, CombineOp.Widen); - } - - public override Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { - //Contract.Requires((bToResult != null)); - //Contract.Requires((b != null)); - //Contract.Requires((aToResult != null)); - - //Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen); - } - - public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - if (IsBottom(e)) { - return e; - } - Elt newValue = new Elt(e.Count, false); - for (int i = 0; i < this.lattices.Count; i++) { - newValue[i] = SubLattice(i).Eliminate(cce.NonNull(e[i]), variable); - } - return newValue; - } - - - public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(element != null); - //Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - if (IsBottom(e)) { - return e; - } - Elt newValue = new Elt(e.Count, false); - for (int i = 0; i < this.lattices.Count; i++) { - newValue[i] = SubLattice(i).Constrain(cce.NonNull(e[i]), expr); - } - return newValue; - } - - - public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - if (IsBottom(e)) { - return e; - } - Elt newValue = new Elt(e.Count, false); - for (int i = 0; i < this.lattices.Count; i++) { - newValue[i] = SubLattice(i).Rename(cce.NonNull(e[i]), oldName, newName); - } - return newValue; - } - - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - bool result = false; - - for (int i = 0; i < this.lattices.Count; i++) { - result = (result || SubLattice(i).Understands(f, args)); - } - - return result; - } - - - public override string/*!*/ ToString(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - return e.ToString(); - } - - - public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - IExpr result = propExprFactory.True; - for (int i = 0; i < e.Count; i++) { - IExpr conjunct = SubLattice(i).ToPredicate(cce.NonNull(e[i])); - Contract.Assert(conjunct != null); - - result = Prop.SimplifiedAnd(propExprFactory, conjunct, result); - } - return result; - } - - /// - /// Return an expression that is equivalent to the given expression that does not - /// contain the given variable according to the lattice element and queryable. - /// - /// Simply asks each sublattice to try to generate an equivalent expression. We - /// do not try to combine information to infer new equivalences here. - /// - /// The lattice element. - /// A queryable for asking addtional information. - /// The expression to find an equivalent expression. - /// The variable to eliminate. - /// - /// An equivalent expression to without - /// or null if not possible. - /// - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ element, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(element != null); - Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); - - for (int i = 0; i < e.Count; i++) { - IExpr equivexpr = SubLattice(i).EquivalentExpr(cce.NonNull(e[i]), q, expr, var, prohibitedVars); - - if (equivexpr != null) - return equivexpr; - } - - return null; - } - - - public override Answer CheckPredicate(Element/*!*/ element, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(element != null); - Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); - - for (int i = 0; i < e.Count; i++) { - Answer ans = SubLattice(i).CheckPredicate(cce.NonNull(e[i]), pred); - - if (ans == Answer.Yes || ans == Answer.No) - return ans; - } - - return Answer.Maybe; - } - - - public override Answer CheckVariableDisequality(Element/*!*/ element, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(element != null); - Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); - - for (int i = 0; i < e.Count; i++) { - Answer ans = SubLattice(i).CheckVariableDisequality(cce.NonNull(e[i]), var1, var2); - - if (ans == Answer.Yes || ans == Answer.No) - return ans; - } - - return Answer.Maybe; - } - - - - public override void Validate() { - base.Validate(); - foreach (Lattice/*!*/ l in lattices) { - Contract.Assert(l != null); - l.Validate(); - } - } - - /// - /// The enumeration over a MultiLattice is its sublattices. - /// - /// An enumerator over the sublattices. - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - public IEnumerator/**//*!*/ GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - return lattices.GetEnumerator(); - } - - /// - /// Return an enumerable over a mapping of sublattices to the their corresponding - /// lattice elements given a MultiLattice element. - /// - /// The MultiLattice element. - /// - /// An enumerable that yields an IDictionaryEnumerator over the - /// (Lattice, Lattice.Element) pairs. - /// - public IEnumerable/*!*/ Subelements(Element/*!*/ element) { - Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - return new SubelementsEnumerable(this, (Elt/*!*/)cce.NonNull(element)); - } - - /// - /// An enumerator over the sublattices and elements. - /// - private sealed class SubelementsEnumerable : IEnumerable { - private sealed class SubelementsEnumerator : IDictionaryEnumerator { - private readonly IEnumerator/**//*!*/ multiLatticeIter; - private readonly IEnumerator/**//*!*/ multiElementIter; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(multiElementIter != null); - Contract.Invariant(multiLatticeIter != null); - } - - - public SubelementsEnumerator(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { - Contract.Requires(multiElement != null); - Contract.Requires(multiLattice != null); - Contract.Requires(multiElement.elementPerLattice != null); - this.multiLatticeIter = multiLattice.lattices.GetEnumerator(); - this.multiElementIter = multiElement.elementPerLattice.GetEnumerator(); - // base(); - } - - public DictionaryEntry Entry { - get { - return new DictionaryEntry(cce.NonNull(multiLatticeIter.Current), multiElementIter.Current); - } - } - - public object Key { - get { - return multiLatticeIter.Current; - } - } - - public object Value { - get { - return multiElementIter.Current; - } - } - - public object Current { - get { - return this.Entry; - } - } - - public bool MoveNext() { - return multiLatticeIter.MoveNext() && multiElementIter.MoveNext(); - } - - public void Reset() { - multiLatticeIter.Reset(); - multiElementIter.Reset(); - } - } - - private MultiLattice/*!*/ multiLattice; - private Elt/*!*/ multiElement; - - public SubelementsEnumerable(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { - Contract.Requires(multiElement != null); - Contract.Requires(multiLattice != null); - this.multiLattice = multiLattice; - this.multiElement = multiElement; - // base(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - public IEnumerator/*!*/ GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - return new SubelementsEnumerator(multiLattice, multiElement); - } - } - - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using Microsoft.AbstractInterpretationFramework.Collections; + + using Microsoft.Boogie; + + using ISet = Microsoft.Boogie.GSet; + using Set = Microsoft.Boogie.GSet; + + + /// + /// The cartesian product lattice. + /// + public class MultiLattice : Lattice, IEnumerable { + internal class Elt : Element { + public /*MaybeNull*/Element[] elementPerLattice; + + public Elt(int domainCount, bool isBottom) { + this.elementPerLattice = (domainCount == 0 && isBottom) ? null : new Element[domainCount]; + } + + private Elt(Elt/*!*/ other) { + Contract.Requires(other != null); + Element[] otherEPL = other.elementPerLattice; + if (otherEPL != null) { + Element[] newEPL = new Element[otherEPL.Length]; + for (int i = 0; i < newEPL.Length; i++) { + newEPL[i] = (Element)(cce.NonNull(otherEPL[i])).Clone(); + } + this.elementPerLattice = newEPL; + } + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new Elt(this); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + // string s = "MultiLattice+Elt{"; + // string sep = ""; + // Element[] epl = this.elementPerLattice; + // if (epl != null) + // { + // foreach (Element! e in epl) + // { + // s += sep + e.ToString(); + // sep = ", "; + // } + // } + // return s + "}"; + if (elementPerLattice == null) + return ""; + System.Text.StringBuilder buffer = new System.Text.StringBuilder(); + for (int i = 0; i < this.Count; i++) { + if (i > 0) + buffer.Append("; "); + buffer.AppendFormat("{0}", elementPerLattice[i]); + } + return buffer.ToString(); + } + + public override void Dump(string/*!*/ msg) { + //Contract.Requires(msg != null); + System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg); + Element[] epl = this.elementPerLattice; + if (epl != null) { + foreach (Element/*!*/ e in epl) { + Contract.Assert(e != null); + e.Dump(msg); + } + } + } + + [Pure] + public override ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + List/*!*/ list = new List(); + for (int i = 0; i < this.Count; i++) { + list.AddRange(cce.NonNull(this[i]).FreeVariables()); + } + return cce.NonNull(list.AsReadOnly()); + } + + public static Elt/*!*/ Top(ArrayList/**//*!*/ lattices) { + Contract.Requires(lattices != null); + Contract.Ensures(Contract.Result() != null); + Elt multiValue = new Elt(lattices.Count, false); + for (int i = 0; i < lattices.Count; i++) { + Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); + multiValue[d.Index] = d.Top; + } + Debug.Assert(multiValue.IsValid); + return multiValue; + } + + + public static Elt/*!*/ Bottom(ArrayList/**//*!*/ lattices) { + Contract.Requires(lattices != null); + Contract.Ensures(Contract.Result() != null); + Elt multiValue = new Elt(lattices.Count, true); + for (int i = 0; i < lattices.Count; i++) { + Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); + multiValue[d.Index] = d.Bottom; + } + Debug.Assert(multiValue.IsValid); + return multiValue; + } + + public bool IsValid { + get { + if (this.elementPerLattice == null) { + return true; /*bottom*/ + } + + Element[] epl = this.elementPerLattice; + for (int i = 0; i < epl.Length; i++) { + if (epl[i] == null) { + return false; + } + } + return true; + } + } + + public int Count { + get { + return this.elementPerLattice == null ? 0 : this.elementPerLattice.Length; + } + } + + public bool Contains(int i) { + return 0 <= i && i < this.Count; + } + + public Element this[int i] // just syntactic sugar + { + get { + Element[] epl = this.elementPerLattice; + return epl == null ? null : epl[i]; + } + set { + Element[] epl = this.elementPerLattice; + if (epl == null) + return; + epl[i] = value; + } + } + + } // class + + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattices != null); + Contract.Invariant(propExprFactory != null); + } + + ArrayList/**//*!*/ lattices = new ArrayList(); + + private readonly IPropExprFactory/*!*/ propExprFactory; + + + public MultiLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory) + : base(valueExprFactory) { + Contract.Requires(valueExprFactory != null); + Contract.Requires(propExprFactory != null); + this.propExprFactory = propExprFactory; + // base(valueExprFactory); + } + + + + public void AddLattice(Lattice lattice) { + this.lattices.Add(lattice); + } + + private Lattice/*!*/ SubLattice(int i) { + Contract.Ensures(Contract.Result() != null); + return (Lattice/*!*/)cce.NonNull(this.lattices[i]); + } + + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Top(this.lattices); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Bottom(this.lattices); + } + } + + + + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + // The program is errorneous/nonterminating if any subdomain knows it is. + // + if (e.elementPerLattice == null) { + return true; + } + for (int i = 0; i < e.Count; i++) { + if (SubLattice(i).IsBottom(cce.NonNull(e[i]))) { + return true; + } + } + return false; + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + if (e.elementPerLattice == null) { + return false; + } + // The multidomain knows nothing about the program only if no subdomain + // knows anything about it. + // + for (int i = 0; i < e.Count; i++) { + if (!SubLattice(i).IsTop(cce.NonNull(e[i]))) { + return false; + } + } + return true; + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + for (int i = 0; i < a.Count; i++) { + Element thisElement = cce.NonNull(a[i]); + Element thatElement = cce.NonNull(b[i]); + if (thisElement.GetType() != thatElement.GetType()) { + throw new System.InvalidOperationException( + "AtMost called on MultiDomain objects with different lattices" + ); + } + if (!SubLattice(i).LowerThan(thisElement, thatElement)) { + return false; + } + } + return true; + } + + protected override bool AtMost(Element/*!*/ first, ICombineNameMap/*!*/ firstToResult, Element/*!*/ second, ICombineNameMap/*!*/ secondToResult) { + //Contract.Requires(secondToResult != null); + //Contract.Requires(second != null); + //Contract.Requires(firstToResult != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + for (int i = 0; i < a.Count; i++) { + Element thisElement = cce.NonNull(a[i]); + Element thatElement = cce.NonNull(b[i]); + if (thisElement.GetType() != thatElement.GetType()) { + throw new System.InvalidOperationException( + "AtMost called on MultiDomain objects with different lattices" + ); + } + if (!SubLattice(i).LowerThan(thisElement, firstToResult, thatElement, secondToResult)) { + return false; + } + } + return true; + } + + + private enum CombineOp { + Meet, + Join, + Widen + } + + private Element/*!*/ Combine(Element/*!*/ first, ICombineNameMap/*?*/ firstToResult, Element/*!*/ second, ICombineNameMap/*?*/ secondToResult, CombineOp c) { + Contract.Requires(second != null); + Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + int unionCount = System.Math.Max(a.Count, b.Count); + Elt combined = new Elt(unionCount, IsBottom(a) && IsBottom(b)); + for (int i = 0; i < unionCount; i++) { + bool thisExists = a.Contains(i); + bool thatExists = b.Contains(i); + + if (thisExists && thatExists) { + Lattice.Element suba = a[i]; + Lattice.Element subb = b[i]; + Contract.Assert(suba != null && subb != null); + + switch (c) { + case CombineOp.Meet: + combined[i] = SubLattice(i).Meet(suba, subb); + break; + case CombineOp.Join: + if (firstToResult != null && secondToResult != null) + combined[i] = SubLattice(i).Join(suba, firstToResult, subb, secondToResult); + else + combined[i] = SubLattice(i).Join(suba, subb); + break; + case CombineOp.Widen: + if (firstToResult != null && secondToResult != null) + combined[i] = SubLattice(i).Widen(suba, firstToResult, subb, secondToResult); + else + combined[i] = SubLattice(i).Widen(suba, subb); + break; + } + } else if (thisExists) { + combined[i] = a[i]; + } else { + combined[i] = b[i]; + } + } + Debug.Assert(combined.IsValid); + return combined; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, null, b, null, CombineOp.Join); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + //Contract.Requires((bToResult != null)); + //Contract.Requires((b != null)); + //Contract.Requires((aToResult != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, aToResult, b, bToResult, CombineOp.Join); + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, null, b, null, CombineOp.Meet); + } + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, null, b, null, CombineOp.Widen); + } + + public override Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + //Contract.Requires((bToResult != null)); + //Contract.Requires((b != null)); + //Contract.Requires((aToResult != null)); + + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen); + } + + public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + if (IsBottom(e)) { + return e; + } + Elt newValue = new Elt(e.Count, false); + for (int i = 0; i < this.lattices.Count; i++) { + newValue[i] = SubLattice(i).Eliminate(cce.NonNull(e[i]), variable); + } + return newValue; + } + + + public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + if (IsBottom(e)) { + return e; + } + Elt newValue = new Elt(e.Count, false); + for (int i = 0; i < this.lattices.Count; i++) { + newValue[i] = SubLattice(i).Constrain(cce.NonNull(e[i]), expr); + } + return newValue; + } + + + public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + if (IsBottom(e)) { + return e; + } + Elt newValue = new Elt(e.Count, false); + for (int i = 0; i < this.lattices.Count; i++) { + newValue[i] = SubLattice(i).Rename(cce.NonNull(e[i]), oldName, newName); + } + return newValue; + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + bool result = false; + + for (int i = 0; i < this.lattices.Count; i++) { + result = (result || SubLattice(i).Understands(f, args)); + } + + return result; + } + + + public override string/*!*/ ToString(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + return e.ToString(); + } + + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + IExpr result = propExprFactory.True; + for (int i = 0; i < e.Count; i++) { + IExpr conjunct = SubLattice(i).ToPredicate(cce.NonNull(e[i])); + Contract.Assert(conjunct != null); + + result = Prop.SimplifiedAnd(propExprFactory, conjunct, result); + } + return result; + } + + /// + /// Return an expression that is equivalent to the given expression that does not + /// contain the given variable according to the lattice element and queryable. + /// + /// Simply asks each sublattice to try to generate an equivalent expression. We + /// do not try to combine information to infer new equivalences here. + /// + /// The lattice element. + /// A queryable for asking addtional information. + /// The expression to find an equivalent expression. + /// The variable to eliminate. + /// + /// An equivalent expression to without + /// or null if not possible. + /// + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ element, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, Set/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + IExpr equivexpr = SubLattice(i).EquivalentExpr(cce.NonNull(e[i]), q, expr, var, prohibitedVars); + + if (equivexpr != null) + return equivexpr; + } + + return null; + } + + + public override Answer CheckPredicate(Element/*!*/ element, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + Answer ans = SubLattice(i).CheckPredicate(cce.NonNull(e[i]), pred); + + if (ans == Answer.Yes || ans == Answer.No) + return ans; + } + + return Answer.Maybe; + } + + + public override Answer CheckVariableDisequality(Element/*!*/ element, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + Answer ans = SubLattice(i).CheckVariableDisequality(cce.NonNull(e[i]), var1, var2); + + if (ans == Answer.Yes || ans == Answer.No) + return ans; + } + + return Answer.Maybe; + } + + + + public override void Validate() { + base.Validate(); + foreach (Lattice/*!*/ l in lattices) { + Contract.Assert(l != null); + l.Validate(); + } + } + + /// + /// The enumeration over a MultiLattice is its sublattices. + /// + /// An enumerator over the sublattices. + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + public IEnumerator/**//*!*/ GetEnumerator() { + Contract.Ensures(Contract.Result() != null); + return lattices.GetEnumerator(); + } + + /// + /// Return an enumerable over a mapping of sublattices to the their corresponding + /// lattice elements given a MultiLattice element. + /// + /// The MultiLattice element. + /// + /// An enumerable that yields an IDictionaryEnumerator over the + /// (Lattice, Lattice.Element) pairs. + /// + public IEnumerable/*!*/ Subelements(Element/*!*/ element) { + Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + return new SubelementsEnumerable(this, (Elt/*!*/)cce.NonNull(element)); + } + + /// + /// An enumerator over the sublattices and elements. + /// + private sealed class SubelementsEnumerable : IEnumerable { + private sealed class SubelementsEnumerator : IDictionaryEnumerator { + private readonly IEnumerator/**//*!*/ multiLatticeIter; + private readonly IEnumerator/**//*!*/ multiElementIter; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(multiElementIter != null); + Contract.Invariant(multiLatticeIter != null); + } + + + public SubelementsEnumerator(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { + Contract.Requires(multiElement != null); + Contract.Requires(multiLattice != null); + Contract.Requires(multiElement.elementPerLattice != null); + this.multiLatticeIter = multiLattice.lattices.GetEnumerator(); + this.multiElementIter = multiElement.elementPerLattice.GetEnumerator(); + // base(); + } + + public DictionaryEntry Entry { + get { + return new DictionaryEntry(cce.NonNull(multiLatticeIter.Current), multiElementIter.Current); + } + } + + public object Key { + get { + return multiLatticeIter.Current; + } + } + + public object Value { + get { + return multiElementIter.Current; + } + } + + public object Current { + get { + return this.Entry; + } + } + + public bool MoveNext() { + return multiLatticeIter.MoveNext() && multiElementIter.MoveNext(); + } + + public void Reset() { + multiLatticeIter.Reset(); + multiElementIter.Reset(); + } + } + + private MultiLattice/*!*/ multiLattice; + private Elt/*!*/ multiElement; + + public SubelementsEnumerable(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { + Contract.Requires(multiElement != null); + Contract.Requires(multiLattice != null); + this.multiLattice = multiLattice; + this.multiElement = multiElement; + // base(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + public IEnumerator/*!*/ GetEnumerator() { + Contract.Ensures(Contract.Result() != null); + return new SubelementsEnumerator(multiLattice, multiElement); + } + } + + + } +} diff --git a/Source/AIFramework/Mutable.cs b/Source/AIFramework/Mutable.cs index 7592aa6a..fff0476e 100644 --- a/Source/AIFramework/Mutable.cs +++ b/Source/AIFramework/Mutable.cs @@ -1,137 +1,137 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework.Collections { - using System.Collections; - using System.Diagnostics.Contracts; - - /// - /// Extend sets for using as a IWorkList. - /// - public class WorkSet : Microsoft.Boogie.GSet, Microsoft.Boogie.IWorkList { - - // See Bug #148 for an explanation of why this is here. - // Without it, the contract inheritance rules will complain since it - // has nowhere to attach the out-of-band contract it gets from - // ICollection.Count that it gets from IWorkList. - public override int Count { - get { - return base.Count; - } - } - - [Pure] - public bool IsEmpty() { - return Count == 0; - } - - /// - /// Pull an element out of the workset. - /// - public object Pull() { - IEnumerator iter = GetEnumerator(); - iter.MoveNext(); - - object result = cce.NonNull(iter.Current); - Remove(result); - - return result; - } - - bool Microsoft.Boogie.IWorkList.Add(object o) { - if (o == null) - throw new System.ArgumentNullException(); - this.Add(o); - return true; - } - bool Microsoft.Boogie.IWorkList.AddAll(IEnumerable objs) { - if (objs == null) - throw new System.ArgumentNullException(); - return this.AddAll(objs); - } - - // ICollection members - public void CopyTo(System.Array/*!*/ a, int i) { - //Contract.Requires(a != null); - if (this.Count > a.Length - i) - throw new System.ArgumentException(); - int j = i; - foreach (object o in this) { - a.SetValue(o, j++); - } - return; - } - object/*!*/ ICollection.SyncRoot { - [Pure] - get { - Contract.Ensures(Contract.Result() != null); - return this; - } - } - public bool IsSynchronized { - get { - return false; - } - } - - } -} - -namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { - using System.Collections.Generic; - - public class HashMultiset { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(dict != null); - } - - private readonly IDictionary/*!*/ dict; - - //Contract.Invariant(Contract.ForAll(dict , entry => entry.Value >= 1)); - - public HashMultiset() { - this.dict = new Dictionary(); - // base(); - } - - public HashMultiset(int size) { - this.dict = new Dictionary(size); - // base(); - } - - public void Add(T t) { - cce.BeginExpose(this); - { - if (dict.ContainsKey(t)) { - dict[t] = dict[t] + 1; - } else { - dict.Add(t, 1); - } - } - cce.EndExpose(); - } - - public void Remove(T t) { - if (dict.ContainsKey(t)) { - cce.BeginExpose(this); - { - int count = dict[t]; - if (count == 1) { - dict.Remove(t); - } else { - dict[t] = count - 1; - } - } - cce.EndExpose(); - } - } - - public bool Contains(T t) { - return dict.ContainsKey(t); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework.Collections { + using System.Collections; + using System.Diagnostics.Contracts; + + /// + /// Extend sets for using as a IWorkList. + /// + public class WorkSet : Microsoft.Boogie.GSet, Microsoft.Boogie.IWorkList { + + // See Bug #148 for an explanation of why this is here. + // Without it, the contract inheritance rules will complain since it + // has nowhere to attach the out-of-band contract it gets from + // ICollection.Count that it gets from IWorkList. + public override int Count { + get { + return base.Count; + } + } + + [Pure] + public bool IsEmpty() { + return Count == 0; + } + + /// + /// Pull an element out of the workset. + /// + public object Pull() { + IEnumerator iter = GetEnumerator(); + iter.MoveNext(); + + object result = cce.NonNull(iter.Current); + Remove(result); + + return result; + } + + bool Microsoft.Boogie.IWorkList.Add(object o) { + if (o == null) + throw new System.ArgumentNullException(); + this.Add(o); + return true; + } + bool Microsoft.Boogie.IWorkList.AddAll(IEnumerable objs) { + if (objs == null) + throw new System.ArgumentNullException(); + return this.AddAll(objs); + } + + // ICollection members + public void CopyTo(System.Array/*!*/ a, int i) { + //Contract.Requires(a != null); + if (this.Count > a.Length - i) + throw new System.ArgumentException(); + int j = i; + foreach (object o in this) { + a.SetValue(o, j++); + } + return; + } + object/*!*/ ICollection.SyncRoot { + [Pure] + get { + Contract.Ensures(Contract.Result() != null); + return this; + } + } + public bool IsSynchronized { + get { + return false; + } + } + + } +} + +namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { + using System.Collections.Generic; + + public class HashMultiset { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(dict != null); + } + + private readonly IDictionary/*!*/ dict; + + //Contract.Invariant(Contract.ForAll(dict , entry => entry.Value >= 1)); + + public HashMultiset() { + this.dict = new Dictionary(); + // base(); + } + + public HashMultiset(int size) { + this.dict = new Dictionary(size); + // base(); + } + + public void Add(T t) { + cce.BeginExpose(this); + { + if (dict.ContainsKey(t)) { + dict[t] = dict[t] + 1; + } else { + dict.Add(t, 1); + } + } + cce.EndExpose(); + } + + public void Remove(T t) { + if (dict.ContainsKey(t)) { + cce.BeginExpose(this); + { + int count = dict[t]; + if (count == 1) { + dict.Remove(t); + } else { + dict[t] = count - 1; + } + } + cce.EndExpose(); + } + } + + public bool Contains(T t) { + return dict.ContainsKey(t); + } + } +} diff --git a/Source/AIFramework/Polyhedra/LinearConstraint.cs b/Source/AIFramework/Polyhedra/LinearConstraint.cs index ab5e14f8..82264364 100644 --- a/Source/AIFramework/Polyhedra/LinearConstraint.cs +++ b/Source/AIFramework/Polyhedra/LinearConstraint.cs @@ -1,545 +1,545 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework { - using System; - //using System.Compiler; - using System.Collections; - using Microsoft.Basetypes; +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System; + //using System.Compiler; + using System.Collections; + using Microsoft.Basetypes; using Set = Microsoft.Boogie.GSet; - using IMutableSet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - - - /// - /// Represents a single linear constraint, coefficients are stored as Rationals. - /// - public class LinearConstraint { - - public enum ConstraintRelation { - EQ, // equal - LE, // less-than or equal - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(coefficients != null); - } - - public readonly ConstraintRelation Relation; - internal Hashtable /*IVariable->Rational*//*!*/ coefficients = new Hashtable /*IVariable->Rational*/ (); - internal Rational rhs; - - public LinearConstraint(ConstraintRelation rel) { - Relation = rel; - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - string s = null; - foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) { - if (s == null) { - s = ""; - } else { - s += " + "; - } - s += String.Format("{0}*{1}", entry.Value, entry.Key); - } - System.Diagnostics.Debug.Assert(s != null, "malformed LinearConstraint: no variables"); - s += String.Format(" {0} {1}", Relation == ConstraintRelation.EQ ? "==" : "<=", rhs); - return s; - } - - -#if DONT_KNOW_HOW_TO_TAKE_THE_TYPE_OF_AN_IVARIABLE_YET - public bool IsOverIntegers - { - get - { - foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) - { - IVariable var = (IVariable)entry.Key; - if ( ! var.TypedIdent.Type.IsInt) { return false; } - } - return true; - } - } -#endif - - - /// - /// Note: This method requires that all dimensions are of type Variable, something that's - /// not required elsewhere in this class. - /// - /// - public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr leftSum = null; - IExpr rightSum = null; - foreach (DictionaryEntry /*object->Rational*/ entry in coefficients) { - IVariable var = (IVariable)entry.Key; - Rational coeff = (Rational)(cce.NonNull(entry.Value)); - if (coeff.IsPositive) { - leftSum = AddTerm(factory, leftSum, coeff, var); - } else if (coeff.IsNegative) { - rightSum = AddTerm(factory, rightSum, -coeff, var); - } else { - // ignore the term is coeff==0 - } - } - - if (leftSum == null && rightSum == null) { - // there are no variables in this constraint - if (Relation == ConstraintRelation.EQ ? rhs.IsZero : rhs.IsNonNegative) { - return factory.True; - } else { - return factory.False; - } - } - - if (leftSum == null || (rightSum != null && rhs.IsNegative)) { - // show the constant on the left side - leftSum = AddTerm(factory, leftSum, -rhs, null); - } else if (rightSum == null || rhs.IsPositive) { - // show the constant on the right side - rightSum = AddTerm(factory, rightSum, rhs, null); - } - - Contract.Assert(leftSum != null); - Contract.Assert(rightSum != null); - return Relation == ConstraintRelation.EQ ? factory.Eq(leftSum, rightSum) : factory.AtMost(leftSum, rightSum); - } - - /// - /// Returns an expression that denotes sum + r*x. - /// If sum==null, drops the "sum +". - /// If x==null, drops the "*x". - /// if x!=null and r==1, drops the "r*". - /// - /// - /// - /// - /// - static IExpr/*!*/ AddTerm(ILinearExprFactory/*!*/ factory, /*MayBeNull*/ IExpr sum, Rational r, /*MayBeNull*/ IVariable x) { - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - IExpr/*!*/ product = factory.Term(r, x); - Contract.Assert(product != null); - if (sum == null) { - return product; - } else { - return factory.Add(sum, product); - } - } - public System.Collections.Generic.IEnumerable GetDefinedDimensionsGeneric() { - Contract.Ensures(Contract.Result>() != null); - foreach (IVariable/*!*/ dim in coefficients.Keys) { - Contract.Assert(dim != null); - yield return dim; - } - } - public ISet /*IVariable!*//*!*/ GetDefinedDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count); - int j = 0; - foreach (IVariable/*!*/ dim in coefficients.Keys) { - Contract.Assert(dim != null); - dims.Add(dim); - j++; - } - System.Diagnostics.Debug.Assert(j == coefficients.Count); - return dims; - } - - /// - /// Returns true iff all of the coefficients in the constraint are 0. In that - /// case, the constraint has the form 0 <= C for some constant C; hence, the - /// constraint is either unsatisfiable or trivially satisfiable. - /// - /// - public bool IsConstant() { - foreach (Rational coeff in coefficients.Values) { - if (coeff.IsNonZero) { - return false; - } - } - return true; - } - - /// - /// For an equality constraint, returns 0 == rhs. - /// For an inequality constraint, returns 0 <= rhs. - /// - public bool IsConstantSatisfiable() { - if (Relation == ConstraintRelation.EQ) { - return rhs.IsZero; - } else { - return rhs.IsNonNegative; - } - } - - /// - /// Returns 0 if "this" and "c" are not equivalent constraints. If "this" and "c" - /// are equivalent constraints, the non-0 return value "m" satisfies "this == m*c". - /// - /// - /// - public Rational IsEquivalent(LinearConstraint/*!*/ c) { - Contract.Requires(c != null); - // "m" is the scale factor. If it is 0, it hasn't been used yet. If it - // is non-0, it will remain that value throughout, and it then says that - // for every dimension "d", "this[d] == m * c[d]". - Rational m = Rational.ZERO; - - ArrayList /*IVariable*/ dd = new ArrayList /*IVariable*/ (); - foreach (IVariable/*!*/ d in this.GetDefinedDimensions()) { - Contract.Assert(d != null); - if (!dd.Contains(d)) { - dd.Add(d); - } - } - foreach (IVariable/*!*/ d in c.GetDefinedDimensions()) { - Contract.Assert(d != null); - if (!dd.Contains(d)) { - dd.Add(d); - } - } - - foreach (IVariable/*!*/ d in dd) { - Contract.Assert(d != null); - Rational a = this[d]; - Rational b = c[d]; - - if (a.IsZero || b.IsZero) { - if (a.IsNonZero || b.IsNonZero) { - return Rational.ZERO; // not equivalent - } - } else if (m.IsZero) { - m = a / b; - } else if (a != m * b) { - return Rational.ZERO; // not equivalent - } - } - - // we expect there to have been some non-zero coefficient, so "m" should have been used by now - System.Diagnostics.Debug.Assert(m.IsNonZero); - - // finally, check the rhs - if (this.rhs == m * c.rhs) { - return m; // equivalent - } else { - return Rational.ZERO; // not equivalent - } - } - - /// - /// Splits an equality constraint into two inequality constraints, the conjunction of - /// which equals the equality constraint. Assumes "this" is a equality constraint. - /// - /// - /// - public void GenerateInequalityConstraints(out LinearConstraint a, out LinearConstraint b) { - System.Diagnostics.Debug.Assert(this.Relation == ConstraintRelation.EQ); - - a = new LinearConstraint(ConstraintRelation.LE); - a.coefficients = (Hashtable)this.coefficients.Clone(); - a.rhs = this.rhs; - - b = new LinearConstraint(ConstraintRelation.LE); - b.coefficients = new Hashtable /*IVariable->Rational*/ (); - foreach (DictionaryEntry entry in this.coefficients) { - b.coefficients[entry.Key] = -(Rational)(cce.NonNull(entry.Value)); - } - b.rhs = -this.rhs; - } - - public void SetCoefficient(IVariable/*!*/ dimension, Rational coefficient) { - Contract.Requires(dimension != null); - coefficients[dimension] = coefficient; - } - - /// - /// Removes dimension "dim" from the constraint. Only dimensions with coefficient 0 can - /// be removed. - /// - /// - public void RemoveDimension(IVariable/*!*/ dim) { - Contract.Requires(dim != null); - object val = coefficients[dim]; - if (val != null) { -#if FIXED_SERIALIZER - Contract.Assert(((Rational)val).IsZero); -#endif - coefficients.Remove(dim); - } - } - - /// - /// The getter returns 0 if the dimension is not present. - /// - public Rational this[IVariable/*!*/ dimension] { - get { - Contract.Requires(dimension != null); - - - object z = coefficients[dimension]; - if (z == null) { - return Rational.ZERO; - } else { - return (Rational)z; - } - } - set { - SetCoefficient(dimension, value); - } - } - - public LinearConstraint Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - object /*Rational*/ z = coefficients[oldName]; - if (z == null) { - return this; - } else { - System.Diagnostics.Debug.Assert(z is Rational); - Hashtable /*IVariable->Rational*/ newCoeffs = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(coefficients.Clone()); - newCoeffs.Remove(oldName); - newCoeffs.Add(newName, z); - - LinearConstraint lc = new LinearConstraint(this.Relation); - lc.coefficients = newCoeffs; - lc.rhs = this.rhs; - return lc; - } - } - - public LinearConstraint Clone() { - LinearConstraint z = new LinearConstraint(Relation); - z.coefficients = (Hashtable /*IVariable->Rational*/)this.coefficients.Clone(); - z.rhs = this.rhs; - return z; - } - - /// - /// Returns a constraint like "this", but with the given relation "r". - /// - /// - public LinearConstraint/*!*/ ChangeRelation(ConstraintRelation rel) { - Contract.Ensures(Contract.Result() != null); - if (Relation == rel) { - return this; - } else { - LinearConstraint z = new LinearConstraint(rel); - z.coefficients = (Hashtable)this.coefficients.Clone(); - z.rhs = this.rhs; - return z; - } - } - - /// - /// Returns a constraint like "this", but, conceptually, with the inequality relation >=. - /// - /// - public LinearConstraint/*!*/ ChangeRelationToAtLeast() { - Contract.Ensures(Contract.Result() != null); - LinearConstraint z = new LinearConstraint(ConstraintRelation.LE); - foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients) { - z.coefficients.Add(entry.Key, -(Rational)(cce.NonNull(entry.Value))); - } - z.rhs = -this.rhs; - return z; - } - - /// - /// Returns the left-hand side of the constraint evaluated at the point "v". - /// Any coordinate not present in "v" is treated as if it were 0. - /// Stated differently, this routine treats the left-hand side of the constraint - /// as a row vector and "v" as a column vector, and then returns the dot-product - /// of the two. - /// - /// - /// - public Rational EvaluateLhs(FrameElement/*!*/ v) { - Contract.Requires(v != null); - Rational q = Rational.ZERO; - foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients) { - IVariable dim = (IVariable/*!*/)cce.NonNull(term.Key); - Rational a = (Rational)(cce.NonNull(term.Value)); - Rational x = v[dim]; - q += a * x; - } - return q; - } - - /// - /// Determines whether or not a given vertex or ray saturates the constraint. - /// - /// - /// true if "fe" is a vertex; false if "fe" is a ray - /// - public bool IsSaturatedBy(FrameElement/*!*/ fe, bool vertex) { - Contract.Requires(fe != null); - Rational lhs = EvaluateLhs(fe); - Rational rhs = vertex ? this.rhs : Rational.ZERO; - return lhs == rhs; - } - - /// - /// Changes the current constraint A*X <= B into (A + m*aa)*X <= B + m*bb, - /// where "cc" is the constraint aa*X <= bb. - /// - /// - /// - /// - public void AddMultiple(Rational m, LinearConstraint/*!*/ cc) { - Contract.Requires(cc != null); - foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients) { - IVariable dim = (IVariable)entry.Key; - Rational d = m * (Rational)(cce.NonNull(entry.Value)); - if (d.IsNonZero) { - object prev = coefficients[dim]; - if (prev == null) { - coefficients[dim] = d; - } else { - coefficients[dim] = (Rational)prev + d; - } - } - } - rhs += m * cc.rhs; - } - - /// - /// Try to reduce the magnitude of the coefficients used. - /// Has a side effect on the coefficients, but leaves the meaning of the linear constraint - /// unchanged. - /// - public void Normalize() { - // compute the gcd of the numerators and the gcd of the denominators - Rational gcd = rhs; - foreach (Rational r in coefficients.Values) { - gcd = Rational.Gcd(gcd, r); - } - // Change all coefficients, to divide their numerators with gcdNum and to - // divide their denominators with gcdDen. - Hashtable /*IVariable->Rational*/ newCoefficients = new Hashtable /*IVariable->Rational*/ (coefficients.Count); - foreach (DictionaryEntry /*IVarianble->Rational*/ e in coefficients) { - Rational r = (Rational)(cce.NonNull(e.Value)); - if (r.IsNonZero) { - newCoefficients.Add(e.Key, Rational.FromBignums(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator)); - } else { - newCoefficients.Add(e.Key, r); - } - } - - coefficients = newCoefficients; - rhs = rhs.IsNonZero ? Rational.FromBignums(rhs.Numerator / gcd.Numerator, rhs.Denominator / gcd.Denominator) : rhs; - } - } - - /// - /// Represents a frame element (vector of dimension/value tuples). Used only - /// internally in class LinearConstraintSystem and its communication with class - /// LinearConstraint. - /// - public class FrameElement { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(terms != null); - } - - Hashtable /*IVariable->Rational*//*!*/ terms = new Hashtable /*IVariable->Rational*/ (); - - /// - /// Constructs an empty FrameElement. To add dimensions, call AddCoordinate after construction. - /// - public FrameElement() { - } - - /// - /// This method is to be thought of as being part of the FrameElement object's construction process. - /// Assumes "dimension" is not already in FrameElement. - /// - /// - /// - public void AddCoordinate(IVariable/*!*/ dimension, Rational value) { - Contract.Requires(dimension != null); - terms.Add(dimension, value); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - string s = null; - foreach (DictionaryEntry item in terms) { - if (s == null) { - s = "("; - } else { - s += ", "; - } - s += String.Format("<{0},{1}>", item.Key, (Rational)(cce.NonNull(item.Value))); - } - if (s == null) { - s = "("; - } - return s + ")"; - } - - public IMutableSet /*IVariable!*//*!*/ GetDefinedDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (terms.Count); - foreach (IVariable/*!*/ dim in terms.Keys) { - Contract.Assert(dim != null); - dims.Add(dim); - } - System.Diagnostics.Debug.Assert(dims.Count == terms.Count); - return dims; - } - - /// - /// The getter returns the value at the given dimension, or 0 if that dimension is not defined. - /// - public Rational this[IVariable/*!*/ dimension] { - get { - //Contract.Ensures(Contract.Result() != null); - object z = terms[dimension]; - if (z == null) { - return Rational.ZERO; - } else { - return (Rational)z; - } - } - set { - terms[dimension] = value; - } - } - - public FrameElement Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - object /*Rational*/ z = terms[oldName]; - if (z == null) { - return this; - } else { - System.Diagnostics.Debug.Assert(z is Rational); - Hashtable /*IVariable->Rational*/ newTerms = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(terms.Clone()); - newTerms.Remove(oldName); - newTerms.Add(newName, z); - - FrameElement fe = new FrameElement(); - fe.terms = newTerms; - return fe; - } - } - - public FrameElement Clone() { - FrameElement z = new FrameElement(); - z.terms = (Hashtable /*IVariable->Rational*/)this.terms.Clone(); - return z; - } - } -} + using IMutableSet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + + + /// + /// Represents a single linear constraint, coefficients are stored as Rationals. + /// + public class LinearConstraint { + + public enum ConstraintRelation { + EQ, // equal + LE, // less-than or equal + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(coefficients != null); + } + + public readonly ConstraintRelation Relation; + internal Hashtable /*IVariable->Rational*//*!*/ coefficients = new Hashtable /*IVariable->Rational*/ (); + internal Rational rhs; + + public LinearConstraint(ConstraintRelation rel) { + Relation = rel; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + string s = null; + foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) { + if (s == null) { + s = ""; + } else { + s += " + "; + } + s += String.Format("{0}*{1}", entry.Value, entry.Key); + } + System.Diagnostics.Debug.Assert(s != null, "malformed LinearConstraint: no variables"); + s += String.Format(" {0} {1}", Relation == ConstraintRelation.EQ ? "==" : "<=", rhs); + return s; + } + + +#if DONT_KNOW_HOW_TO_TAKE_THE_TYPE_OF_AN_IVARIABLE_YET + public bool IsOverIntegers + { + get + { + foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients) + { + IVariable var = (IVariable)entry.Key; + if ( ! var.TypedIdent.Type.IsInt) { return false; } + } + return true; + } + } +#endif + + + /// + /// Note: This method requires that all dimensions are of type Variable, something that's + /// not required elsewhere in this class. + /// + /// + public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr leftSum = null; + IExpr rightSum = null; + foreach (DictionaryEntry /*object->Rational*/ entry in coefficients) { + IVariable var = (IVariable)entry.Key; + Rational coeff = (Rational)(cce.NonNull(entry.Value)); + if (coeff.IsPositive) { + leftSum = AddTerm(factory, leftSum, coeff, var); + } else if (coeff.IsNegative) { + rightSum = AddTerm(factory, rightSum, -coeff, var); + } else { + // ignore the term is coeff==0 + } + } + + if (leftSum == null && rightSum == null) { + // there are no variables in this constraint + if (Relation == ConstraintRelation.EQ ? rhs.IsZero : rhs.IsNonNegative) { + return factory.True; + } else { + return factory.False; + } + } + + if (leftSum == null || (rightSum != null && rhs.IsNegative)) { + // show the constant on the left side + leftSum = AddTerm(factory, leftSum, -rhs, null); + } else if (rightSum == null || rhs.IsPositive) { + // show the constant on the right side + rightSum = AddTerm(factory, rightSum, rhs, null); + } + + Contract.Assert(leftSum != null); + Contract.Assert(rightSum != null); + return Relation == ConstraintRelation.EQ ? factory.Eq(leftSum, rightSum) : factory.AtMost(leftSum, rightSum); + } + + /// + /// Returns an expression that denotes sum + r*x. + /// If sum==null, drops the "sum +". + /// If x==null, drops the "*x". + /// if x!=null and r==1, drops the "r*". + /// + /// + /// + /// + /// + static IExpr/*!*/ AddTerm(ILinearExprFactory/*!*/ factory, /*MayBeNull*/ IExpr sum, Rational r, /*MayBeNull*/ IVariable x) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + IExpr/*!*/ product = factory.Term(r, x); + Contract.Assert(product != null); + if (sum == null) { + return product; + } else { + return factory.Add(sum, product); + } + } + public System.Collections.Generic.IEnumerable GetDefinedDimensionsGeneric() { + Contract.Ensures(Contract.Result>() != null); + foreach (IVariable/*!*/ dim in coefficients.Keys) { + Contract.Assert(dim != null); + yield return dim; + } + } + public ISet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count); + int j = 0; + foreach (IVariable/*!*/ dim in coefficients.Keys) { + Contract.Assert(dim != null); + dims.Add(dim); + j++; + } + System.Diagnostics.Debug.Assert(j == coefficients.Count); + return dims; + } + + /// + /// Returns true iff all of the coefficients in the constraint are 0. In that + /// case, the constraint has the form 0 <= C for some constant C; hence, the + /// constraint is either unsatisfiable or trivially satisfiable. + /// + /// + public bool IsConstant() { + foreach (Rational coeff in coefficients.Values) { + if (coeff.IsNonZero) { + return false; + } + } + return true; + } + + /// + /// For an equality constraint, returns 0 == rhs. + /// For an inequality constraint, returns 0 <= rhs. + /// + public bool IsConstantSatisfiable() { + if (Relation == ConstraintRelation.EQ) { + return rhs.IsZero; + } else { + return rhs.IsNonNegative; + } + } + + /// + /// Returns 0 if "this" and "c" are not equivalent constraints. If "this" and "c" + /// are equivalent constraints, the non-0 return value "m" satisfies "this == m*c". + /// + /// + /// + public Rational IsEquivalent(LinearConstraint/*!*/ c) { + Contract.Requires(c != null); + // "m" is the scale factor. If it is 0, it hasn't been used yet. If it + // is non-0, it will remain that value throughout, and it then says that + // for every dimension "d", "this[d] == m * c[d]". + Rational m = Rational.ZERO; + + ArrayList /*IVariable*/ dd = new ArrayList /*IVariable*/ (); + foreach (IVariable/*!*/ d in this.GetDefinedDimensions()) { + Contract.Assert(d != null); + if (!dd.Contains(d)) { + dd.Add(d); + } + } + foreach (IVariable/*!*/ d in c.GetDefinedDimensions()) { + Contract.Assert(d != null); + if (!dd.Contains(d)) { + dd.Add(d); + } + } + + foreach (IVariable/*!*/ d in dd) { + Contract.Assert(d != null); + Rational a = this[d]; + Rational b = c[d]; + + if (a.IsZero || b.IsZero) { + if (a.IsNonZero || b.IsNonZero) { + return Rational.ZERO; // not equivalent + } + } else if (m.IsZero) { + m = a / b; + } else if (a != m * b) { + return Rational.ZERO; // not equivalent + } + } + + // we expect there to have been some non-zero coefficient, so "m" should have been used by now + System.Diagnostics.Debug.Assert(m.IsNonZero); + + // finally, check the rhs + if (this.rhs == m * c.rhs) { + return m; // equivalent + } else { + return Rational.ZERO; // not equivalent + } + } + + /// + /// Splits an equality constraint into two inequality constraints, the conjunction of + /// which equals the equality constraint. Assumes "this" is a equality constraint. + /// + /// + /// + public void GenerateInequalityConstraints(out LinearConstraint a, out LinearConstraint b) { + System.Diagnostics.Debug.Assert(this.Relation == ConstraintRelation.EQ); + + a = new LinearConstraint(ConstraintRelation.LE); + a.coefficients = (Hashtable)this.coefficients.Clone(); + a.rhs = this.rhs; + + b = new LinearConstraint(ConstraintRelation.LE); + b.coefficients = new Hashtable /*IVariable->Rational*/ (); + foreach (DictionaryEntry entry in this.coefficients) { + b.coefficients[entry.Key] = -(Rational)(cce.NonNull(entry.Value)); + } + b.rhs = -this.rhs; + } + + public void SetCoefficient(IVariable/*!*/ dimension, Rational coefficient) { + Contract.Requires(dimension != null); + coefficients[dimension] = coefficient; + } + + /// + /// Removes dimension "dim" from the constraint. Only dimensions with coefficient 0 can + /// be removed. + /// + /// + public void RemoveDimension(IVariable/*!*/ dim) { + Contract.Requires(dim != null); + object val = coefficients[dim]; + if (val != null) { +#if FIXED_SERIALIZER + Contract.Assert(((Rational)val).IsZero); +#endif + coefficients.Remove(dim); + } + } + + /// + /// The getter returns 0 if the dimension is not present. + /// + public Rational this[IVariable/*!*/ dimension] { + get { + Contract.Requires(dimension != null); + + + object z = coefficients[dimension]; + if (z == null) { + return Rational.ZERO; + } else { + return (Rational)z; + } + } + set { + SetCoefficient(dimension, value); + } + } + + public LinearConstraint Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + object /*Rational*/ z = coefficients[oldName]; + if (z == null) { + return this; + } else { + System.Diagnostics.Debug.Assert(z is Rational); + Hashtable /*IVariable->Rational*/ newCoeffs = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(coefficients.Clone()); + newCoeffs.Remove(oldName); + newCoeffs.Add(newName, z); + + LinearConstraint lc = new LinearConstraint(this.Relation); + lc.coefficients = newCoeffs; + lc.rhs = this.rhs; + return lc; + } + } + + public LinearConstraint Clone() { + LinearConstraint z = new LinearConstraint(Relation); + z.coefficients = (Hashtable /*IVariable->Rational*/)this.coefficients.Clone(); + z.rhs = this.rhs; + return z; + } + + /// + /// Returns a constraint like "this", but with the given relation "r". + /// + /// + public LinearConstraint/*!*/ ChangeRelation(ConstraintRelation rel) { + Contract.Ensures(Contract.Result() != null); + if (Relation == rel) { + return this; + } else { + LinearConstraint z = new LinearConstraint(rel); + z.coefficients = (Hashtable)this.coefficients.Clone(); + z.rhs = this.rhs; + return z; + } + } + + /// + /// Returns a constraint like "this", but, conceptually, with the inequality relation >=. + /// + /// + public LinearConstraint/*!*/ ChangeRelationToAtLeast() { + Contract.Ensures(Contract.Result() != null); + LinearConstraint z = new LinearConstraint(ConstraintRelation.LE); + foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients) { + z.coefficients.Add(entry.Key, -(Rational)(cce.NonNull(entry.Value))); + } + z.rhs = -this.rhs; + return z; + } + + /// + /// Returns the left-hand side of the constraint evaluated at the point "v". + /// Any coordinate not present in "v" is treated as if it were 0. + /// Stated differently, this routine treats the left-hand side of the constraint + /// as a row vector and "v" as a column vector, and then returns the dot-product + /// of the two. + /// + /// + /// + public Rational EvaluateLhs(FrameElement/*!*/ v) { + Contract.Requires(v != null); + Rational q = Rational.ZERO; + foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients) { + IVariable dim = (IVariable/*!*/)cce.NonNull(term.Key); + Rational a = (Rational)(cce.NonNull(term.Value)); + Rational x = v[dim]; + q += a * x; + } + return q; + } + + /// + /// Determines whether or not a given vertex or ray saturates the constraint. + /// + /// + /// true if "fe" is a vertex; false if "fe" is a ray + /// + public bool IsSaturatedBy(FrameElement/*!*/ fe, bool vertex) { + Contract.Requires(fe != null); + Rational lhs = EvaluateLhs(fe); + Rational rhs = vertex ? this.rhs : Rational.ZERO; + return lhs == rhs; + } + + /// + /// Changes the current constraint A*X <= B into (A + m*aa)*X <= B + m*bb, + /// where "cc" is the constraint aa*X <= bb. + /// + /// + /// + /// + public void AddMultiple(Rational m, LinearConstraint/*!*/ cc) { + Contract.Requires(cc != null); + foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients) { + IVariable dim = (IVariable)entry.Key; + Rational d = m * (Rational)(cce.NonNull(entry.Value)); + if (d.IsNonZero) { + object prev = coefficients[dim]; + if (prev == null) { + coefficients[dim] = d; + } else { + coefficients[dim] = (Rational)prev + d; + } + } + } + rhs += m * cc.rhs; + } + + /// + /// Try to reduce the magnitude of the coefficients used. + /// Has a side effect on the coefficients, but leaves the meaning of the linear constraint + /// unchanged. + /// + public void Normalize() { + // compute the gcd of the numerators and the gcd of the denominators + Rational gcd = rhs; + foreach (Rational r in coefficients.Values) { + gcd = Rational.Gcd(gcd, r); + } + // Change all coefficients, to divide their numerators with gcdNum and to + // divide their denominators with gcdDen. + Hashtable /*IVariable->Rational*/ newCoefficients = new Hashtable /*IVariable->Rational*/ (coefficients.Count); + foreach (DictionaryEntry /*IVarianble->Rational*/ e in coefficients) { + Rational r = (Rational)(cce.NonNull(e.Value)); + if (r.IsNonZero) { + newCoefficients.Add(e.Key, Rational.FromBignums(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator)); + } else { + newCoefficients.Add(e.Key, r); + } + } + + coefficients = newCoefficients; + rhs = rhs.IsNonZero ? Rational.FromBignums(rhs.Numerator / gcd.Numerator, rhs.Denominator / gcd.Denominator) : rhs; + } + } + + /// + /// Represents a frame element (vector of dimension/value tuples). Used only + /// internally in class LinearConstraintSystem and its communication with class + /// LinearConstraint. + /// + public class FrameElement { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(terms != null); + } + + Hashtable /*IVariable->Rational*//*!*/ terms = new Hashtable /*IVariable->Rational*/ (); + + /// + /// Constructs an empty FrameElement. To add dimensions, call AddCoordinate after construction. + /// + public FrameElement() { + } + + /// + /// This method is to be thought of as being part of the FrameElement object's construction process. + /// Assumes "dimension" is not already in FrameElement. + /// + /// + /// + public void AddCoordinate(IVariable/*!*/ dimension, Rational value) { + Contract.Requires(dimension != null); + terms.Add(dimension, value); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + string s = null; + foreach (DictionaryEntry item in terms) { + if (s == null) { + s = "("; + } else { + s += ", "; + } + s += String.Format("<{0},{1}>", item.Key, (Rational)(cce.NonNull(item.Value))); + } + if (s == null) { + s = "("; + } + return s + ")"; + } + + public IMutableSet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (terms.Count); + foreach (IVariable/*!*/ dim in terms.Keys) { + Contract.Assert(dim != null); + dims.Add(dim); + } + System.Diagnostics.Debug.Assert(dims.Count == terms.Count); + return dims; + } + + /// + /// The getter returns the value at the given dimension, or 0 if that dimension is not defined. + /// + public Rational this[IVariable/*!*/ dimension] { + get { + //Contract.Ensures(Contract.Result() != null); + object z = terms[dimension]; + if (z == null) { + return Rational.ZERO; + } else { + return (Rational)z; + } + } + set { + terms[dimension] = value; + } + } + + public FrameElement Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + object /*Rational*/ z = terms[oldName]; + if (z == null) { + return this; + } else { + System.Diagnostics.Debug.Assert(z is Rational); + Hashtable /*IVariable->Rational*/ newTerms = (Hashtable/*!*/ /*IVariable->Rational*/)cce.NonNull(terms.Clone()); + newTerms.Remove(oldName); + newTerms.Add(newName, z); + + FrameElement fe = new FrameElement(); + fe.terms = newTerms; + return fe; + } + } + + public FrameElement Clone() { + FrameElement z = new FrameElement(); + z.terms = (Hashtable /*IVariable->Rational*/)this.terms.Clone(); + return z; + } + } +} diff --git a/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs b/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs index 74e36eae..59aadb86 100644 --- a/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs +++ b/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs @@ -1,1756 +1,1756 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System; - //using Microsoft.SpecSharp.Collections; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - - using IMutableSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - /// - /// Represents a system of linear constraints (constraint/frame representations). - /// - public class LinearConstraintSystem { - // -------------------------------------------------------------------------------------------------------- - // ------------------ Data structure ---------------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public /*maybe null*/ ArrayList /*LinearConstraint!*/ Constraints; - /*maybe null*/ - ArrayList /*FrameElement!*/ FrameVertices; - /*maybe null*/ - ArrayList /*FrameElement!*/ FrameRays; - IMutableSet/*IVariable!*//*!*/ FrameDimensions; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(FrameDimensions != null); - } - - /*maybe null*/ - ArrayList /*FrameElement!*/ FrameLines; - // Invariant: Either all of Constraints, FrameVertices, FrameRays, and FrameLines are - // null, or all are non-null. - // Invariant: Any dimension mentioned in Constraints, FrameVertices, FrameRays, or - // FrameLines is mentioned in FrameDimensions. - // The meaning of FrameDimensions is that for any dimension x not in FrameDimensions, - // there is an implicit line along dimension x (that is, ()). - - void CheckInvariant() { - if (Constraints == null) { - System.Diagnostics.Debug.Assert(FrameVertices == null); - System.Diagnostics.Debug.Assert(FrameRays == null); - System.Diagnostics.Debug.Assert(FrameLines == null); - System.Diagnostics.Debug.Assert(FrameDimensions.Count == 0); - } else { - System.Diagnostics.Debug.Assert(FrameVertices != null); - System.Diagnostics.Debug.Assert(FrameRays != null); - System.Diagnostics.Debug.Assert(FrameLines != null); - - foreach (LinearConstraint/*!*/ cc in Constraints) { - Contract.Assert(cc != null); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(cc.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - Contract.Assert(cc.coefficients.Count != 0); - } - foreach (ArrayList /*FrameElement*//*!*/ FrameComponent in new ArrayList /*FrameElement*/ [] { FrameVertices, FrameRays, FrameLines }) { - Contract.Assert(FrameComponent != null); - foreach (FrameElement fe in FrameComponent) { - if (fe == null) - continue; -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(fe.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - } - } - } - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Constructors ------------------------------------------------------------------------ - // -------------------------------------------------------------------------------------------------------- - - /// - /// Creates a LinearConstraintSystem representing the bottom element, that is, representing - /// an unsatisfiable system of constraints. - /// - [NotDelayed] - public LinearConstraintSystem() { - FrameDimensions = new HashSet /*IVariable!*/ (); - //:base(); - CheckInvariant(); - } - - /// - /// Constructs a linear constraint system with constraints "cs". - /// The constructor captures all constraints in "cs". - /// - /// - [NotDelayed] - public LinearConstraintSystem(ArrayList /*LinearConstraint!*//*!*/ cs) { - Contract.Requires(cs != null); -#if BUG_159_HAS_BEEN_FIXED - Contract.Requires(Contract.ForAll(cs) , cc=> cc.coefficients.Count != 0); -#endif - - ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count); - foreach (LinearConstraint/*!*/ cc in cs) { - Contract.Assert(cc != null); - constraints.Add(cc); - } - Constraints = constraints; - FrameDimensions = new HashSet /*IVariable!*/ (); // to please compiler; this value will be overridden in the call to GenerateFrameConstraints below - //:base(); - - GenerateFrameFromConstraints(); - SimplifyConstraints(); - CheckInvariant(); -#if DEBUG_PRINT - Console.WriteLine("LinearConstraintSystem: constructor produced:"); - Dump(); -#endif - } - - /// - /// Constructs a linear constraint system corresponding to given vertex. This constructor - /// is only used in the test harness--it is not needed for abstract interpretation. - /// - /// - [NotDelayed] - LinearConstraintSystem(FrameElement/*!*/ v) { - Contract.Requires(v != null); - IMutableSet/*!*/ frameDims = v.GetDefinedDimensions(); - Contract.Assert(frameDims != null); - ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ (); - foreach (IVariable/*!*/ dim in frameDims) { - Contract.Assert(dim != null); - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - lc.SetCoefficient(dim, Rational.ONE); - lc.rhs = v[dim]; - constraints.Add(lc); - } - FrameDimensions = frameDims; - Constraints = constraints; - - ArrayList /*FrameElement*/ frameVertices = new ArrayList /*FrameElement*/ (); - frameVertices.Add(v); - FrameVertices = frameVertices; - - FrameRays = new ArrayList /*FrameElement*/ (); - FrameLines = new ArrayList /*FrameElement*/ (); - - //:base(); - CheckInvariant(); - } - - void ChangeIntoBottom() { - Constraints = null; - FrameVertices = null; - FrameRays = null; - FrameLines = null; - FrameDimensions.Clear(); // no implicit lines - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Public operations and their support routines ---------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public bool IsBottom() { - return Constraints == null; - } - - public bool IsTop() { - return Constraints != null && Constraints.Count == 0; - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - if (Constraints == null) { - return ""; - } else if (Constraints.Count == 0) { - return ""; - } else { - string z = null; - foreach (LinearConstraint/*!*/ lc in Constraints) { - Contract.Assert(lc != null); - string s = lc.ToString(); - if (z == null) { - z = s; - } else { - z += " AND " + s; - } - } - Contract.Assert(z != null); - return z; - } - } - - - public ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - List list = new List(); - foreach (IVariable/*!*/ v in FrameDimensions) { - Contract.Assert(v != null); - list.Add(v); - } - return cce.NonNull(list.AsReadOnly()); - } - - /// - /// Note: This method requires that all dimensions are of type Variable, something that's - /// not required elsewhere in this class. - /// - /// - public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - Contract.Ensures(Contract.Result() != null); - if (this.Constraints == null) { - return factory.False; - } - if (this.Constraints.Count == 0) { - return factory.True; - } - - IExpr result = null; - foreach (LinearConstraint/*!*/ lc in Constraints) { - Contract.Assert(lc != null); - IExpr conjunct = lc.ConvertToExpression(factory); - result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result); - } - Contract.Assert(result != null); - return result; - } - - - /* IsSubset(): determines if 'lcs' is a subset of 'this' - * -- See Cousot/Halbwachs 1978, section - */ - public bool IsSubset(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - if (lcs.IsBottom()) { - return true; - } else if (this.IsBottom()) { - return false; -#if DEBUG -#else - } else if (this.IsTop()) { // optimization -- this case not needed for correctness - return true; - } else if (lcs.IsTop()) { // optimization -- this case not needed for correctness - return false; -#endif - } else { - // phase 0: check if frame dimensions are a superset of the constraint dimensions - ISet /*IVariable!*//*!*/ frameDims = lcs.GetDefinedDimensions(); - Contract.Assert(frameDims != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: IsSubset:"); - Console.WriteLine(" --- this:"); - this.Dump(); - Console.WriteLine(" --- lcs:"); - lcs.Dump(); - Console.WriteLine(" ---"); -#endif - foreach (LinearConstraint/*!*/ cc in cce.NonNull(this.Constraints)) { - Contract.Assert(cc != null); -#if DEBUG_PRINT - Console.WriteLine(" cc: {0}", cc); - Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions()); -#endif - - if (!Contract.ForAll(cc.GetDefinedDimensionsGeneric(), var => frameDims.Contains(var))) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 0 subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - - // phase 1: check frame vertices against each constraint... - foreach (FrameElement/*!*/ v in cce.NonNull(lcs.FrameVertices)) { - Contract.Assert(v != null); - foreach (LinearConstraint/*!*/ cc in this.Constraints) { - Contract.Assert(cc != null); - Rational q = cc.EvaluateLhs(v); - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - if (!(q <= cc.rhs)) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 1a subset violated, return false from IsSubset"); -#endif - return false; - } - } else { - if (!(q == cc.rhs)) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 1b subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - } - - // phase 2: check frame rays against each constraint... - // To check if a ray "r" falls within a constraint "cc", we add the vector "r" to - // any point "p" on the side of the half-space or plane described by constraint, and - // then check if the resulting point satisfies the constraint. That is, we check (for - // an inequality constraint with coefficients a1,a2,...,an and right-hand side - // constant C): - // a1*(r1+p1) + a2*(r2+p2) + ... + an*(rn+pn) <= C - // Equivalently: - // a1*r1 + a2*r2 + ... + an*rn + a1*p1 + a2*p2 + ... + an*pn <= C - // To find a point "p", we can pick out a coordinate, call it 1, with a non-zero - // coefficient in the constraint, and then choose "p" as the point that has the - // value C/a1 in coordinate 1 and has 0 in all other coordinates. We then check: - // a1*r1 + a2*r2 + ... + an*rn + a1*(C/a1) + a2*0 + ... + an*0 <= C - // which simplifies to: - // a1*r1 + a2*r2 + ... + an*rn + C <= C - // which in turn simplifies to: - // a1*r1 + a2*r2 + ... + an*rn <= 0 - // If the constraint is an equality constraint, we simply replace "<=" with "==" - // above. - foreach (FrameElement/*!*/ r in cce.NonNull(lcs.FrameRays)) { - Contract.Assert(r != null); - System.Diagnostics.Debug.Assert(r != null, "encountered a null ray..."); - foreach (LinearConstraint/*!*/ cc in this.Constraints) { - Contract.Assert(cc != null); - System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); - Rational q = cc.EvaluateLhs(r); - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - if (q.IsPositive) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 2a subset violated, return false from IsSubset"); -#endif - return false; - } - } else { - if (q.IsNonZero) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 2b subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - } - - // phase 3: check frame lines against each constraint... - // To check if a line "L" falls within a constraint "cc", we check if both the - // vector "L" and "-L", interpreted as rays, fall within the constraint. From - // the discussion above, this means we check the following two properties: - // a1*L1 + a2*L2 + ... + an*Ln <= 0 (*) - // a1*(-L1) + a2*(-L2) + ... + an*(-Ln) <= 0 - // The second of these lines can be rewritten as: - // - a1*L1 - a2*L2 - ... - an*Ln <= 0 - // which is equivalent to: - // -1 * (a1*L1 + a2*L2 + ... + an*Ln) <= 0 - // Multiplying both sides by -1 and flipping the direction of the inequality, - // we have: - // a1*L1 + a2*L2 + ... + an*Ln >= 0 (**) - // Putting (*) and (**) together, we conclude that we need to check: - // a1*L1 + a2*L2 + ... + an*Ln == 0 - // If the constraint is an equality constraint, we end up with the same equation. - foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { - Contract.Assert(line != null); - System.Diagnostics.Debug.Assert(line != null, "encountered a null line..."); - foreach (LinearConstraint/*!*/ cc in this.Constraints) { - Contract.Assert(cc != null); - System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); - Rational q = cc.EvaluateLhs(line); - if (q.IsNonZero) { -#if DEBUG_PRINT - Console.WriteLine(" ---> phase 3 subset violated, return false from IsSubset"); -#endif - return false; - } - } - } - -#if DEBUG_PRINT - Console.WriteLine(" ---> IsSubset returns true"); -#endif - return true; - } - - public LinearConstraintSystem/*!*/ Meet(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - Contract.Requires((this.Constraints != null)); - Contract.Requires((lcs.Constraints != null)); - Contract.Ensures(Contract.Result() != null); - ArrayList /*LinearConstraint*/ clist = new ArrayList(this.Constraints.Count + lcs.Constraints.Count); - clist.AddRange(this.Constraints); - clist.AddRange(lcs.Constraints); - return new LinearConstraintSystem(clist); - } - -#if DEBUG_PRINT - public LinearConstraintSystem Join(LinearConstraintSystem lcs) - { - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Join"); - Console.WriteLine("Join: this="); - Dump(); - Console.WriteLine("Join: lcs="); - lcs.Dump(); - LinearConstraintSystem z = JoinX(lcs); - Console.WriteLine("----------Join------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Join: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - - /// - /// The join is computed as described in section 4.4 in Cousot and Halbwachs. - /// - /// - /// -#if DEBUG_PRINT - public LinearConstraintSystem JoinX(LinearConstraintSystem lcs) { -#else - public LinearConstraintSystem/*!*/ Join(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - Contract.Ensures(Contract.Result() != null); -#endif - - if (this.IsBottom()) { - return cce.NonNull(lcs.Clone()); - } else if (lcs.IsBottom()) { - return cce.NonNull(this.Clone()); - } else if (this.IsTop() || lcs.IsTop()) { - return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); - } else { - LinearConstraintSystem/*!*/ z; - // Start from the "larger" of the two frames (this is just a heuristic measure intended - // to save work). - Contract.Assume(this.FrameVertices != null); - Contract.Assume(this.FrameRays != null); - Contract.Assume(this.FrameLines != null); - Contract.Assume(lcs.FrameVertices != null); - Contract.Assume(lcs.FrameRays != null); - Contract.Assume(lcs.FrameLines != null); - if (this.FrameVertices.Count + this.FrameRays.Count + this.FrameLines.Count - this.FrameDimensions.Count < - lcs.FrameVertices.Count + lcs.FrameRays.Count + lcs.FrameLines.Count - lcs.FrameDimensions.Count) { - z = cce.NonNull(lcs.Clone()); - lcs = this; - } else { - z = cce.NonNull(this.Clone()); - } -#if DEBUG_PRINT - Console.WriteLine("DEBUG: LinearConstraintSystem.Join ---------------"); - Console.WriteLine("z:"); - z.Dump(); - Console.WriteLine("lcs:"); - lcs.Dump(); -#endif - - // Start by explicating the implicit lines of z for the dimensions dims(lcs)-dims(z). - foreach (IVariable/*!*/ dim in lcs.FrameDimensions) { - Contract.Assert(dim != null); - if (!z.FrameDimensions.Contains(dim)) { - z.FrameDimensions.Add(dim); - FrameElement line = new FrameElement(); - line.AddCoordinate(dim, Rational.ONE); - // Note: AddLine is not called (because the line already exists in z--it's just that - // it was represented implicitly). Instead, just tack the explicit representation onto - // FrameLines. - Contract.Assume(z.FrameLines != null); - z.FrameLines.Add(line); -#if DEBUG_PRINT - Console.WriteLine("Join: After explicating line: {0}", line); - z.Dump(); -#endif - } - } - - // Now, the vertices, rays, and lines can be added. - foreach (FrameElement/*!*/ v in lcs.FrameVertices) { - Contract.Assert(v != null); - z.AddVertex(v); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding vertex: {0}", v); - z.Dump(); -#endif - } - foreach (FrameElement/*!*/ r in lcs.FrameRays) { - Contract.Assert(r != null); - z.AddRay(r); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding ray: {0}", r); - z.Dump(); -#endif - } - foreach (FrameElement/*!*/ l in lcs.FrameLines) { - Contract.Assert(l != null); - z.AddLine(l); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding line: {0}", l); - z.Dump(); -#endif - } - // also add to z the implicit lines of lcs - foreach (IVariable/*!*/ dim in z.FrameDimensions) { - Contract.Assert(dim != null); - if (!lcs.FrameDimensions.Contains(dim)) { - // "dim" is a dimension that's explicit in "z" but implicit in "lcs" - FrameElement line = new FrameElement(); - line.AddCoordinate(dim, Rational.ONE); - z.AddLine(line); -#if DEBUG_PRINT - Console.WriteLine("Join: After adding lcs's implicit line: {0}", line); - z.Dump(); -#endif - } - } - - z.SimplifyFrame(); - z.SimplifyConstraints(); - z.CheckInvariant(); -#if DEBUG_PRINT - Console.WriteLine("Join: Returning z:"); - z.Dump(); - Console.WriteLine("----------------------------------------"); -#endif - return z; - } - } - -#if DEBUG_PRINT - public LinearConstraintSystem Widen(LinearConstraintSystem lcs) - { - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Widen"); - Console.WriteLine("Widen: this="); - Dump(); - Console.WriteLine("Widen: lcs="); - lcs.Dump(); - LinearConstraintSystem z = WidenX(lcs); - Console.WriteLine("----------Widen------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Widen: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - -#if DEBUG_PRINT - public LinearConstraintSystem WidenX(LinearConstraintSystem lcs){ -#else - public LinearConstraintSystem/*!*/ Widen(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - Contract.Ensures(Contract.Result() != null); -#endif - if (this.IsBottom()) { - return cce.NonNull(lcs.Clone()); - } else if (lcs.IsBottom()) { - return cce.NonNull(this.Clone()); - } else if (this.IsTop() || lcs.IsTop()) { - return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); - } - - // create new LCS, we will add only verified constraints to this... - ArrayList /*LinearConstraint*/ newConstraints = new ArrayList /*LinearConstraint*/ (); - Contract.Assume(this.Constraints != null); - foreach (LinearConstraint/*!*/ ccX in this.Constraints) { - Contract.Assert(ccX != null); - LinearConstraint cc = ccX; -#if DEBUG_PRINT - Console.WriteLine("Widen checking: Starting to check constraint: {0}", cc); -#endif - if (cc.IsConstant()) { - // (Can this ever occur in the stable state of a LinearConstraintSystem? --KRML) - // constraint is unaffected by the frame components -#if DEBUG_PRINT - Console.WriteLine("Widen checking: --Adding it!"); -#endif - newConstraints.Add(cc); - continue; - } - - // PHASE I: verify constraints against all frame vertices... - - foreach (FrameElement/*!*/ vertex in cce.NonNull(lcs.FrameVertices)) { - Contract.Assert(vertex != null); - Rational lhs = cc.EvaluateLhs(vertex); - if (lhs > cc.rhs) { - // the vertex does not satisfy the inequality <= - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out because of vertex: {0}", vertex); -#endif - goto CHECK_NEXT_CONSTRAINT; - } else { - // ... but it does satisfy the inequality >= -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out <= because of vertex: {0}", vertex); -#endif - cc = cc.ChangeRelationToAtLeast(); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with constraint: {0}", cc); -#endif - } - } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs < cc.rhs) { - // the vertex does not satisfy the inequality >=, and the constraint is an equality constraint -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out >= because of vertex: {0}", vertex); -#endif - cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with contraint: {0}", cc); -#endif - } - } - - // PHASE II: verify constraints against all frame rays... - - foreach (FrameElement/*!*/ ray in cce.NonNull(lcs.FrameRays)) { - Contract.Assert(ray != null); - // The following assumes the constraint to have some dimension with a non-zero coefficient - Rational lhs = cc.EvaluateLhs(ray); - if (lhs.IsPositive) { - // the ray does not satisfy the inequality <= - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out because of ray: {0}", ray); -#endif - goto CHECK_NEXT_CONSTRAINT; - } else { - // ... but it does satisfy the inequality >= -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out <= because of ray: {0}", ray); -#endif - cc = cc.ChangeRelationToAtLeast(); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with contraint: {0}", cc); -#endif - } - } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs.IsNegative) { - // the ray does not satisfy the inequality >=, and the constraint is an equality constraint -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out >= because of ray: {0}", ray); -#endif - cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); -#if DEBUG_PRINT - Console.WriteLine("Widen checking: left with constraint: {0}", cc); -#endif - } - } - - // PHASE III: verify constraints against all frame lines... - - foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { - Contract.Assert(line != null); - // The following assumes the constraint to have some dimension with a non-zero coefficient - Rational lhs = cc.EvaluateLhs(line); - if (!lhs.IsZero) { - // The line satisfies neither the inequality <= nor the equality == -#if DEBUG_PRINT - Console.WriteLine("Widen checking: throwing out because of line: {0}", line); -#endif - goto CHECK_NEXT_CONSTRAINT; - } - } - - // constraint has been verified, so add to new constraint system -#if DEBUG_PRINT - Console.WriteLine("Widen checking: --Adding it!"); -#endif - newConstraints.Add(cc); - - CHECK_NEXT_CONSTRAINT: { - } -#if DEBUG_PRINT - Console.WriteLine("Widen checking: done with that constraint"); -#endif - } - - return new LinearConstraintSystem(newConstraints); - } - -#if DEBUG_PRINT - public LinearConstraintSystem Project(IVariable/*!*/ dim){ -Contract.Requires(dim != null); - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Project(dim={0})", dim); - Console.WriteLine("Project: this="); - Dump(); - LinearConstraintSystem z = ProjectX(dim); - Console.WriteLine("----------Project------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Project: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - -#if DEBUG_PRINT - public LinearConstraintSystem ProjectX(IVariable/*!*/ dim){Contract.Requires(dim != null);Contract.Requires(this.Constraints != null); -#else - public LinearConstraintSystem/*!*/ Project(IVariable/*!*/ dim) { - Contract.Requires(dim != null); - Contract.Requires(this.Constraints != null); - Contract.Ensures(Contract.Result() != null); -#endif - - - ArrayList /*LinearConstraint!*//*!*/ cc = Project(dim, Constraints); - Contract.Assert(cc != null); - return new LinearConstraintSystem(cc); - } - -#if DEBUG_PRINT - public LinearConstraintSystem Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName){ -Contract.Requires(newName != null); -Contract.Requires(oldName != null); - Console.WriteLine("==================================================================================="); - Console.WriteLine("DEBUG: Rename(oldName={0}, newName={1})", oldName, newName); - Console.WriteLine("Rename: this="); - Dump(); - LinearConstraintSystem z = RenameX(oldName, newName); - Console.WriteLine("----------Rename------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Console.WriteLine("Rename: result="); - z.Dump(); - Console.WriteLine("==================================================================================="); - return z; - } -#endif - -#if DEBUG_PRINT - public LinearConstraintSystem RenameX(IVariable/*!*/ oldName, IVariable/*!*/ newName){Contract.Requires(oldName != null);Contract.Requires(newName != null); -#else - public LinearConstraintSystem/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(oldName != null); - Contract.Requires(newName != null); - Contract.Ensures(Contract.Result() != null); -#endif - if (this.Constraints == null) { - System.Diagnostics.Debug.Assert(this.FrameVertices == null); - System.Diagnostics.Debug.Assert(this.FrameRays == null); - System.Diagnostics.Debug.Assert(this.FrameLines == null); - return this; - } - IMutableSet /*IVariable!*//*!*/ dims = this.FrameDimensions; - Contract.Assert(dims != null); - if (!dims.Contains(oldName)) { - return this; - } - - LinearConstraintSystem z = new LinearConstraintSystem(); - z.FrameDimensions = cce.NonNull((HashSet/*!*/ /*IVariable!*/)dims.Clone()); - z.FrameDimensions.Remove(oldName); - z.FrameDimensions.Add(newName); - - z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count); - foreach (LinearConstraint/*!*/ lc in cce.NonNull(this.Constraints)) { - Contract.Assert(lc != null); - z.Constraints.Add(lc.Rename(oldName, newName)); - } - z.FrameVertices = RenameInFE(cce.NonNull(this.FrameVertices), oldName, newName); - z.FrameRays = RenameInFE(cce.NonNull(this.FrameRays), oldName, newName); - z.FrameLines = RenameInFE(cce.NonNull(this.FrameLines), oldName, newName); - return z; - } - - static ArrayList /*FrameElement*/ RenameInFE(ArrayList/*!*/ /*FrameElement*/ list, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - Contract.Requires(list != null); - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - ArrayList/*FrameElement!*//*!*/ z = new ArrayList/*FrameElement!*/ (list.Count); - Contract.Assert(z != null); - foreach (FrameElement/*!*/ fe in list) { - Contract.Assert(fe != null); - z.Add(fe.Rename(oldName, newName)); - } - System.Diagnostics.Debug.Assert(z.Count == list.Count); - return z; - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ support routines -------------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - /// - /// Returns a set of constraints that is the given set of constraints with dimension "dim" - /// projected out. See Cousot and Halbwachs, section 3.3.1.1. - /// - /// - /// - /// - static ArrayList /*LinearConstraint!*//*!*/ Project(IVariable/*!*/ dim, ArrayList /*LinearConstraint!*//*!*/ constraints) { - Contract.Requires(constraints != null); - Contract.Requires(dim != null); - Contract.Ensures(Contract.Result() != null); - // Sort the inequality constaints into ones where dimension "dim" is 0, negative, and - // positive, respectively. Put equality constraints with a non-0 "dim" into "eq". - ArrayList /*LinearConstraint!*//*!*/ final = new ArrayList /*LinearConstraint!*/ (); - ArrayList /*LinearConstraint!*//*!*/ negative = new ArrayList /*LinearConstraint!*/ (); - ArrayList /*LinearConstraint!*//*!*/ positive = new ArrayList /*LinearConstraint!*/ (); - ArrayList /*LinearConstraint!*//*!*/ eq = new ArrayList /*LinearConstraint!*/ (); - foreach (LinearConstraint/*!*/ cc in constraints) { - Contract.Assert(cc != null); - Rational coeff = cc[dim]; - if (coeff.IsZero) { - LinearConstraint lc = cce.NonNull(cc.Clone()); - if (!lc.IsConstant()) { - lc.RemoveDimension(dim); - final.Add(lc); - } - } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ) { - eq.Add(cc); - } else if (coeff.IsNegative) { - negative.Add(cc); - } else { - System.Diagnostics.Debug.Assert(coeff.IsPositive); - positive.Add(cc); - } - } - - if (eq.Count != 0) { - LinearConstraint eqConstraint = (LinearConstraint/*!*/)cce.NonNull(eq[eq.Count - 1]); - eq.RemoveAt(eq.Count - 1); - Rational eqC = -eqConstraint[dim]; - - foreach (ArrayList /*LinearConstraint!*/ list in new ArrayList[] { eq, negative, positive }) { - Contract.Assert(list != null); - foreach (LinearConstraint/*!*/ lcX in list) { - Contract.Assert(lcX != null); - LinearConstraint lc = cce.NonNull(lcX.Clone()); - lc.AddMultiple(lc[dim] / eqC, eqConstraint); - System.Diagnostics.Debug.Assert(lc[dim].IsZero); - if (!lc.IsConstant()) { - lc.RemoveDimension(dim); - final.Add(lc); - } else { - System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); - } - } - } - } else { - // Consider all pairs of constraints with (negative,positive) coefficients of "dim". - foreach (LinearConstraint/*!*/ cn in negative) { - Contract.Assert(cn != null); - Rational dn = -cn[dim]; - System.Diagnostics.Debug.Assert(dn.IsNonNegative); - foreach (LinearConstraint/*!*/ cp in positive) { - Contract.Assert(cp != null); - Rational dp = cp[dim]; - - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - lc.AddMultiple(dn, cp); - lc.AddMultiple(dp, cn); - System.Diagnostics.Debug.Assert(lc[dim].IsZero); - if (!lc.IsConstant()) { - lc.RemoveDimension(dim); - final.Add(lc); - } else { - System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); - } - } - } - } - - return final; - } - - /// - /// Initializes FrameVertices, FrameRays, FrameLines, and FrameDimensions, see - /// Cousot and Halbwachs, section 3.4. Any previous values of these fields are - /// ignored and overwritten. - /// - /// If the set of Constraints is unsatisfiable, then "this" is changed into Bottom. - /// - void GenerateFrameFromConstraints() { - if (Constraints == null) { - FrameVertices = null; - FrameRays = null; - FrameLines = null; - FrameDimensions = new HashSet /*IVariable!*/ (); - return; - } - - // Step 1 (see Cousot and Halbwachs, section 3.4.3): create a Simplex Tableau. -#if DEBUG_PRINT - Console.WriteLine("DEBUG: --- GenerateFrameFromConstraint ---"); - Console.WriteLine("Constraints:"); - foreach (LinearConstraint cc in Constraints) - { - Console.WriteLine(" {0}", cc); - } -#endif - SimplexTableau tableau = new SimplexTableau(Constraints); -#if DEBUG_PRINT - Console.WriteLine("Initial tableau:"); - tableau.Dump(); -#endif - FrameDimensions = tableau.GetDimensions(); -#if DEBUG_PRINT - Console.WriteLine("Dimensions:"); - foreach (object dim in FrameDimensions) - { - Console.Write(" {0}", dim); - } - Console.WriteLine(); -#endif - - // Step 3 and 2: Put as many initial variables as possible into basis, then check if - // we reached a feasible basis - tableau.AddInitialVarsToBasis(); -#if DEBUG_PRINT - Console.WriteLine("Tableau after Step 3:"); - tableau.Dump(); -#endif - if (!tableau.IsFeasibleBasis) { - // The polyhedron is empty (according to Cousot and Halbwachs) - ChangeIntoBottom(); - return; - } - - FrameVertices = new ArrayList /*FrameElement*/ (); - FrameRays = new ArrayList /*FrameElement*/ (); - FrameLines = new ArrayList /*FrameElement*/ (); - if (FrameDimensions.Count == 0) { - // top element - return; - } - - if (tableau.AllInitialVarsInBasis) { - // All initial variables are in basis; there are no lines. -#if DEBUG_PRINT - Console.WriteLine("Tableau after Steps 2 and 3 (all initial variables in basis):"); - tableau.Dump(); -#endif - } else { - // There are lines -#if DEBUG_PRINT - Console.WriteLine("Tableau after Steps 2 and 3 (NOT all initial variables in basis--there are lines):"); - tableau.Dump(); -#endif - // Step 4.2: Pick out the lines, then produce the tableau for a new polyhedron without those lines. - ArrayList /*LinearConstraint*/ moreConstraints = cce.NonNull((ArrayList/*!*/ /*LinearConstraint*/)Constraints.Clone()); - tableau.ProduceLines(FrameLines, moreConstraints); - tableau = new SimplexTableau(moreConstraints); -#if DEBUG_PRINT - Console.WriteLine("Lines produced:"); - foreach (FrameElement line in FrameLines) - { - Console.WriteLine(" {0}", line); - } - Console.WriteLine("The new list of constraints is:"); - foreach (LinearConstraint c in moreConstraints) - { - Console.WriteLine(" {0}", c); - } - Console.WriteLine("Tableau after producing lines in Step 4.2:"); - tableau.Dump(); -#endif - - // Repeat step 3 for the new tableau. - // Since the new tableau contains no lines, the following call should cause all initial - // variables to be in basis (see step 4.2 in section 3.4.3 of Cousot and Halbwachs). - tableau.AddInitialVarsToBasis(); - System.Diagnostics.Debug.Assert(tableau.AllInitialVarsInBasis); - System.Diagnostics.Debug.Assert(tableau.IsFeasibleBasis); // the new tableau represents a set of feasible constraints, so this basis should be found to be feasible -#if DEBUG_PRINT - Console.WriteLine("Tableau after all initial variables have been moved into basis:"); - tableau.Dump(); -#endif - } - - // Step 4.1: One vertex has been found. Find all others, too. - tableau.TraverseVertices(FrameVertices, FrameRays); -#if DEBUG_PRINT - Console.WriteLine("Tableau after vertex traversal:"); - tableau.Dump(); -#endif - } - - class LambdaDimension : IVariable { - readonly int id; - static int count = 0; - - /// - /// Return the name of the variable - /// - public string Name { - get { - Contract.Ensures(Contract.Result() != null); - - return this.ToString(); - } - } - - public LambdaDimension() { - id = count; - count++; - } - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "lambda" + id; - } - [Pure] - public object DoVisit(ExprVisitor/*!*/ visitor) { - //Contract.Requires(visitor != null); - return visitor.VisitVariable(this); - } - } - - /// - /// Adds a vertex to the frame of "this" and updates Constraints accordingly, see - /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify - /// Constraints after the operation; that remains the caller's responsibility (which - /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, - /// and AddLine before calling SimplifyConstraints). - /// Assumes Constraints (and the frame fields) to be non-null. - /// - /// - void AddVertex(FrameElement/*!*/ vertex) { - Contract.Requires(vertex != null); - Contract.Requires(this.FrameVertices != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: AddVertex called on {0}", vertex); - Console.WriteLine(" Initial constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - FrameVertices.Add(vertex.Clone()); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(vertex.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - - // We use a new temporary dimension. - IVariable/*!*/ lambda = new LambdaDimension(); - - // We change the constraints A*X <= B into - // A*X + (A*vector - B)*lambda <= A*vector. - // That means that each row k in A (which corresponds to one LinearConstraint - // in Constraints) is changed by adding - // (A*vector - B)[k] * lambda - // to row k and changing the right-hand side of row k to - // (A*vector)[k] - // Note: - // (A*vector - B)[k] - // = { vector subtraction is pointwise } - // (A*vector)[k] - B[k] - // = { A*vector is a row vector whose every row i is the dot-product of - // row i of A with the column vector "vector" } - // A[k]*vector - B[k] - foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { - Contract.Assert(cc != null); - Rational d = cc.EvaluateLhs(vertex); - cc.SetCoefficient(lambda, d - cc.rhs); - cc.rhs = d; - } - - // We also add the constraints that lambda lies between 0 ... - LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - la.SetCoefficient(lambda, Rational.MINUS_ONE); - la.rhs = Rational.ZERO; - Constraints.Add(la); - // ... and 1. - la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - la.SetCoefficient(lambda, Rational.ONE); - la.rhs = Rational.ONE; - Constraints.Add(la); -#if DEBUG_PRINT - Console.WriteLine(" Constraints after addition:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - // Finally, project out the dummy dimension. - Constraints = Project(lambda, Constraints); - -#if DEBUG_PRINT - Console.WriteLine(" Resulting constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - } - - /// - /// Adds a ray to the frame of "this" and updates Constraints accordingly, see - /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify - /// Constraints after the operation; that remains the caller's responsibility (which - /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, - /// and AddLine before calling SimplifyConstraints). - /// Assumes Constraints (and the frame fields) to be non-null. - /// - /// - void AddRay(FrameElement/*!*/ ray) { - Contract.Requires(ray != null); - Contract.Requires(this.FrameRays != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: AddRay called on {0}", ray); - Console.WriteLine(" Initial constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - FrameRays.Add(ray.Clone()); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(ray.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - - // We use a new temporary dimension. - IVariable/*!*/ lambda = new LambdaDimension(); - - // We change the constraints A*X <= B into - // A*X - (A*ray)*lambda <= B. - // That means that each row k in A (which corresponds to one LinearConstraint - // in Constraints) is changed by subtracting - // (A*ray)[k] * lambda - // from row k. - // Note: - // (A*ray)[k] - // = { A*ray is a row vector whose every row i is the dot-product of - // row i of A with the column vector "ray" } - // A[k]*ray - foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { - Contract.Assert(cc != null); - Rational d = cc.EvaluateLhs(ray); - cc.SetCoefficient(lambda, -d); - } - - // We also add the constraints that lambda is at least 0. - LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - la.SetCoefficient(lambda, Rational.MINUS_ONE); - la.rhs = Rational.ZERO; - Constraints.Add(la); -#if DEBUG_PRINT - Console.WriteLine(" Constraints after addition:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - // Finally, project out the dummy dimension. - Constraints = Project(lambda, Constraints); - -#if DEBUG_PRINT - Console.WriteLine(" Resulting constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - } - - /// - /// Adds a line to the frame of "this" and updates Constraints accordingly, see - /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify - /// Constraints after the operation; that remains the caller's responsibility (which - /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, - /// and AddLine before calling SimplifyConstraints). - /// Assumes Constraints (and the frame fields) to be non-null. - /// - /// - void AddLine(FrameElement/*!*/ line) { - Contract.Requires(line != null); - Contract.Requires(this.FrameLines != null); - // Note: The code for AddLine is identical to that of AddRay, except the AddLine - // does not introduce the constraint 0 <= lambda. (One could imagine sharing the - // code between AddRay and AddLine.) -#if DEBUG_PRINT - Console.WriteLine("DEBUG: AddLine called on {0}", line); - Console.WriteLine(" Initial constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - FrameLines.Add(line.Clone()); -#if FIXED_DESERIALIZER - Contract.Assert(Contract.ForAll(line.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); -#endif - - // We use a new temporary dimension. - IVariable/*!*/ lambda = new LambdaDimension(); - - // We change the constraints A*X <= B into - // A*X - (A*line)*lambda <= B. - // That means that each row k in A (which corresponds to one LinearConstraint - // in Constraints) is changed by subtracting - // (A*line)[k] * lambda - // from row k. - // Note: - // (A*line)[k] - // = { A*line is a row vector whose every row i is the dot-product of - // row i of A with the column vector "line" } - // A[k]*line - foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { - Contract.Assert(cc != null); - Rational d = cc.EvaluateLhs(line); - cc.SetCoefficient(lambda, -d); - } - -#if DEBUG_PRINT - Console.WriteLine(" Constraints after addition:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - - // Finally, project out the dummy dimension. - Constraints = Project(lambda, Constraints); - -#if DEBUG_PRINT - Console.WriteLine(" Resulting constraints:"); - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } -#endif - } - - ISet /*IVariable!*//*!*/ GetDefinedDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); - foreach (ArrayList p in new ArrayList[] { FrameVertices, FrameRays, FrameLines }) { - if (p != null) { - foreach (FrameElement/*!*/ element in p) { - Contract.Assert(element != null); - foreach (IVariable/*!*/ dim in element.GetDefinedDimensions()) { - Contract.Assert(dim != null); - dims.Add(dim); - } - } - } - } - return dims; - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Simplification routines ------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - /// - /// Uses the Constraints to simplify the frame. See section 3.4.4 of Cousot and Halbwachs. - /// - void SimplifyFrame() { - Contract.Requires(this.Constraints != null); - SimplificationStatus[]/*!*/ status; - - SimplifyFrameElements(cce.NonNull(FrameVertices), true, Constraints, out status); - RemoveIrrelevantFrameElements(FrameVertices, status, null); - - SimplifyFrameElements(cce.NonNull(FrameRays), false, Constraints, out status); - RemoveIrrelevantFrameElements(FrameRays, status, FrameLines); - } - - enum SimplificationStatus { - Irrelevant, - Relevant, - More - }; - - /// - /// For each i, sets status[i] to: - ///
    - ///
  • Irrelevant if ff[i] is irrelevant
  • - ///
  • Relevant if ff[i] is irrelevant
  • - ///
  • More if vertices is true and ray ff[i] can be replaced by a line ff[i]
  • - ///
- ///
- /// - /// true if "ff" contains vertices; false if "ff" contains rays - /// - /// - static void SimplifyFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, bool vertices, ArrayList/*!*/ /*LinearConstraint*/ constraints, out SimplificationStatus[]/*!*/ status) { - Contract.Requires(ff != null); - Contract.Requires(constraints != null); - Contract.Ensures(Contract.ValueAtReturn(out status) != null); - status = new SimplificationStatus[ff.Count]; - bool[,] sat = new bool[ff.Count, constraints.Count]; - for (int i = 0; i < ff.Count; i++) { - FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]); - int cnt = 0; - for (int c = 0; c < constraints.Count; c++) { - LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(constraints[c]); - bool s = lc.IsSaturatedBy(f, vertices); - if (s) { - sat[i, c] = true; - cnt++; - } - } - if (!vertices && cnt == constraints.Count) { - status[i] = SimplificationStatus.More; - } else { - status[i] = SimplificationStatus.Relevant; - } - } - - CheckPairSimplifications(sat, status); - } - - /// - /// Requires sat.GetLength(0) == status.Length. - /// - /// - /// - static void CheckPairSimplifications(bool[,]/*!*/ sat, SimplificationStatus[]/*!*/ status) { - Contract.Requires(status != null); - Contract.Requires(sat != null); - Contract.Requires(sat.GetLength(0) == status.Length); - int M = sat.GetLength(0); - int N = sat.GetLength(1); - - for (int i = 0; i < M - 1; i++) { - if (status[i] != SimplificationStatus.Relevant) { - continue; - } - for (int j = i + 1; j < M; j++) { - if (status[j] != SimplificationStatus.Relevant) { - continue; - } - // check (sat[i,*] <= sat[j,*]) and (sat[i,*] >= sat[j,*]) - int cmp = 0; // -1: (sat[i,*] <= sat[j,*]), 0: equal, 1: (sat[i,*] >= sat[j,*]) - for (int c = 0; c < N; c++) { - if (cmp < 0) { - if (sat[i, c] && !sat[j, c]) { - // incomparable - goto NEXT_PAIR; - } - } else if (0 < cmp) { - if (!sat[i, c] && sat[j, c]) { - // incomparable - goto NEXT_PAIR; - } - } else if (sat[i, c] != sat[j, c]) { - if (!sat[i, c]) { - cmp = -1; - } else { - cmp = 1; - } - } - } - if (cmp <= 0) { - // sat[i,*] <= sat[j,*] holds, so mark i as irrelevant - status[i] = SimplificationStatus.Irrelevant; - goto NEXT_OUTER; - } else { - // sat[i,*] >= sat[j,*] holds, so mark j as irrelevant - status[j] = SimplificationStatus.Irrelevant; - } - NEXT_PAIR: { - } - } - NEXT_OUTER: { - } - } - } - - static void RemoveIrrelevantFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, SimplificationStatus[]/*!*/ status, - /*maybe null*/ ArrayList /*FrameElement*/ lines) { - Contract.Requires(ff != null); - Contract.Requires(status != null); - Contract.Requires(ff.Count == status.Length); - for (int j = ff.Count - 1; 0 <= j; j--) { - switch (status[j]) { - case SimplificationStatus.Relevant: - break; - case SimplificationStatus.Irrelevant: -#if DEBUG_PRINT - Console.WriteLine("Removing irrelevant {0}: {1}", lines == null ? "vertex" : "ray", ff[j]); -#endif - ff.RemoveAt(j); - break; - case SimplificationStatus.More: - System.Diagnostics.Debug.Assert(lines != null); - FrameElement f = (FrameElement)ff[j]; -#if DEBUG_PRINT - Console.WriteLine("Changing ray into line: {0}", f); -#endif - ff.RemoveAt(j); - Contract.Assert(lines != null); - lines.Add(f); - break; - } - } - } - - /// - /// Uses the frame to simplify Constraints. See section 3.3.1.2 of Cousot and Halbwachs. - /// - /// Note: This code does not necessarily eliminate all irrelevant equalities; Cousot and - /// Halbwachs only claim that the technique eliminates all irrelevant inequalities. - /// - void SimplifyConstraints() { - if (Constraints == null) { - return; - } - Contract.Assume(this.FrameVertices != null); - Contract.Assume(this.FrameRays != null); - - SimplificationStatus[] status = new SimplificationStatus[Constraints.Count]; - /*readonly*/ - int feCount = FrameVertices.Count + FrameRays.Count; - - // Create a table that keeps track of which constraints are satisfied by which vertices and rays - bool[,] sat = new bool[Constraints.Count, FrameVertices.Count + FrameRays.Count]; - for (int i = 0; i < Constraints.Count; i++) { - status[i] = SimplificationStatus.Relevant; - LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); - int cnt = 0; // number of vertices and rays that saturate lc - for (int j = 0; j < FrameVertices.Count; j++) { - FrameElement vertex = (FrameElement/*!*/)cce.NonNull(FrameVertices[j]); - if (lc.IsSaturatedBy(vertex, true)) { - sat[i, j] = true; - cnt++; - } - } - if (cnt == 0) { - // no vertex saturates the constraint, so the constraint is irrelevant - status[i] = SimplificationStatus.Irrelevant; - continue; - } - for (int j = 0; j < FrameRays.Count; j++) { - FrameElement ray = (FrameElement/*!*/)cce.NonNull(FrameRays[j]); - if (lc.IsSaturatedBy(ray, false)) { - sat[i, FrameVertices.Count + j] = true; - cnt++; - } - } - if (cnt == feCount) { - status[i] = SimplificationStatus.More; - } else { - // Cousot and Halbwachs says that all equalities are found in the way we just tested. - // If I understand that right, then we should not get here if the constraint is an - // equality constraint. The following assertion tests my understanding. --KRML - System.Diagnostics.Debug.Assert(lc.Relation == LinearConstraint.ConstraintRelation.LE); - } - } - - CheckPairSimplifications(sat, status); - - // Finally, make the changes to the list of constraints - for (int i = Constraints.Count - 1; 0 <= i; i--) { - switch (status[i]) { - case SimplificationStatus.Relevant: - break; - case SimplificationStatus.Irrelevant: -#if DEBUG_PRINT - Console.WriteLine("Removing irrelevant constraint: {0}", Constraints[i]); -#endif - Constraints.RemoveAt(i); - break; - case SimplificationStatus.More: - LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); - if (lc.Relation == LinearConstraint.ConstraintRelation.LE) { -#if DEBUG_PRINT - Console.WriteLine("Converting the following constraint into an equality: {0}", lc); -#endif - LinearConstraint lcEq = lc.ChangeRelation(LinearConstraint.ConstraintRelation.EQ); - Constraints[i] = lcEq; - } - break; - } - } - - foreach (LinearConstraint/*!*/ lc in Constraints) { - Contract.Assert(lc != null); - lc.Normalize(); - } - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Cloning routines -------------------------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public LinearConstraintSystem/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - LinearConstraintSystem z = new LinearConstraintSystem(); - z.FrameDimensions = (IMutableSet /*IVariable!*//*!*/)cce.NonNull(this.FrameDimensions.Clone()); - if (this.Constraints != null) { - z.Constraints = DeeperListCopy_LC(this.Constraints); - z.FrameVertices = DeeperListCopy_FE(cce.NonNull(this.FrameVertices)); - z.FrameRays = DeeperListCopy_FE(cce.NonNull(this.FrameRays)); - z.FrameLines = DeeperListCopy_FE(cce.NonNull(this.FrameLines)); - } else { - System.Diagnostics.Debug.Assert(this.FrameVertices == null); - System.Diagnostics.Debug.Assert(this.FrameRays == null); - System.Diagnostics.Debug.Assert(this.FrameLines == null); - // the constructor should already have set these fields of z to null - System.Diagnostics.Debug.Assert(z.Constraints == null); - System.Diagnostics.Debug.Assert(z.FrameVertices == null); - System.Diagnostics.Debug.Assert(z.FrameRays == null); - System.Diagnostics.Debug.Assert(z.FrameLines == null); - } - return z; - } - - /// - /// Clones "list" and the elements of "list". - /// - /// - /// - ArrayList /*LinearConstraint*/ DeeperListCopy_LC(ArrayList/*!*/ /*LinearConstraint*/ list) { - Contract.Requires(list != null); - ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count); - foreach (LinearConstraint/*!*/ lc in list) { - Contract.Assert(lc != null); - z.Add(lc.Clone()); - } - System.Diagnostics.Debug.Assert(z.Count == list.Count); - return z; - } - - /// - /// Clones "list" and the elements of "list". - /// - /// - /// - ArrayList /*FrameElement*/ DeeperListCopy_FE(ArrayList/*!*/ /*FrameElement*/ list) { - Contract.Requires(list != null); - ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count); - foreach (FrameElement/*!*/ fe in list) { - Contract.Assert(fe != null); - z.Add(fe.Clone()); - } - System.Diagnostics.Debug.Assert(z.Count == list.Count); - return z; - } - - // -------------------------------------------------------------------------------------------------------- - // ------------------ Debugging and unit test routines ---------------------------------------------------- - // -------------------------------------------------------------------------------------------------------- - - public void Dump() { - Console.WriteLine(" Constraints:"); - if (Constraints == null) { - Console.WriteLine(" "); - } else { - foreach (LinearConstraint cc in Constraints) { - Console.WriteLine(" {0}", cc); - } - } - - Console.WriteLine(" FrameDimensions: {0}", FrameDimensions); - - Console.WriteLine(" FrameVerticies:"); - if (FrameVertices == null) { - Console.WriteLine(" "); - } else { - foreach (FrameElement fe in FrameVertices) { - Console.WriteLine(" {0}", fe); - } - } - - Console.WriteLine(" FrameRays:"); - if (FrameRays == null) { - Console.WriteLine(" "); - } else { - foreach (FrameElement fe in FrameRays) { - Console.WriteLine(" {0}", fe); - } - } - - Console.WriteLine(" FrameLines:"); - if (FrameLines == null) { - Console.WriteLine(" "); - } else { - foreach (FrameElement fe in FrameLines) { - Console.WriteLine(" {0}", fe); - } - } - } - - class TestVariable : IVariable { - readonly string/*!*/ name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(name != null); - } - - - public string/*!*/ Name { - get { - Contract.Ensures(Contract.Result() != null); - - return name; - } - } - - public TestVariable(string/*!*/ name) { - Contract.Requires(name != null); - this.name = name; - } - [Pure] - public object DoVisit(ExprVisitor/*!*/ visitor) { - //Contract.Requires(visitor != null); - return visitor.VisitVariable(this); - } - } - - public static void RunValidationA() { - IVariable/*!*/ dim1 = new TestVariable("X"); - IVariable/*!*/ dim2 = new TestVariable("Y"); - IVariable/*!*/ dim3 = new TestVariable("Z"); - Contract.Assert(dim1 != null); - Contract.Assert(dim2 != null); - Contract.Assert(dim3 != null); - - FrameElement s1 = new FrameElement(); - s1.AddCoordinate(dim1, Rational.ONE); - s1.AddCoordinate(dim2, Rational.MINUS_ONE); - s1.AddCoordinate(dim3, Rational.ZERO); - FrameElement s2 = new FrameElement(); - s2.AddCoordinate(dim1, Rational.MINUS_ONE); - s2.AddCoordinate(dim2, Rational.ONE); - s2.AddCoordinate(dim3, Rational.ZERO); - FrameElement r1 = new FrameElement(); - r1.AddCoordinate(dim1, Rational.ZERO); - r1.AddCoordinate(dim2, Rational.ZERO); - r1.AddCoordinate(dim3, Rational.ONE); - FrameElement d1 = new FrameElement(); - d1.AddCoordinate(dim1, Rational.ONE); - d1.AddCoordinate(dim2, Rational.ONE); - d1.AddCoordinate(dim3, Rational.ZERO); - - // create lcs from frame -- cf. Cousot/Halbwachs 1978, section 3.3.1.1 - LinearConstraintSystem lcs = new LinearConstraintSystem(s1); - lcs.Dump(); - - lcs.AddVertex(s2); - lcs.Dump(); - - lcs.AddRay(r1); - lcs.Dump(); - - lcs.AddLine(d1); - lcs.Dump(); - - lcs.SimplifyConstraints(); - lcs.Dump(); - -#if LATER - lcs.GenerateFrameFromConstraints(); // should give us back the original frame... -#endif - Console.WriteLine("IsSubset? {0}", lcs.IsSubset(lcs.Clone())); - lcs.Dump(); - } - - /// - /// Tests the example in section 3.4.3 of Cousot and Halbwachs. - /// - public static void RunValidationB() { - IVariable/*!*/ X = new TestVariable("X"); - IVariable/*!*/ Y = new TestVariable("Y"); - IVariable/*!*/ Z = new TestVariable("Z"); - Contract.Assert(X != null); - Contract.Assert(Y != null); - Contract.Assert(Z != null); - ArrayList /*LinearConstraint*/ cs = new ArrayList /*LinearConstraint*/ (); - - LinearConstraint c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(X, Rational.MINUS_ONE); - c.SetCoefficient(Y, Rational.ONE); - c.SetCoefficient(Z, Rational.MINUS_ONE); - c.rhs = Rational.ZERO; - cs.Add(c); - - c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(X, Rational.MINUS_ONE); - c.rhs = Rational.MINUS_ONE; - cs.Add(c); - - c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(X, Rational.MINUS_ONE); - c.SetCoefficient(Y, Rational.MINUS_ONE); - c.SetCoefficient(Z, Rational.ONE); - c.rhs = Rational.ZERO; - cs.Add(c); - - c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); - c.SetCoefficient(Y, Rational.MINUS_ONE); - c.SetCoefficient(Z, Rational.ONE); - c.rhs = Rational.FromInt(3); - cs.Add(c); - - LinearConstraintSystem lcs = new LinearConstraintSystem(cs); - Console.WriteLine("==================== The final linear constraint system ===================="); - lcs.Dump(); - } - - public static void RunValidationC() { - // Run the example in section 3.4.3 of Cousot and Halbwachs backwards, that is, from - // from to constraints. - IVariable/*!*/ dim1 = new TestVariable("X"); - IVariable/*!*/ dim2 = new TestVariable("Y"); - IVariable/*!*/ dim3 = new TestVariable("Z"); - Contract.Assert(dim1 != null); - Contract.Assert(dim2 != null); - Contract.Assert(dim3 != null); - - FrameElement s0 = new FrameElement(); - s0.AddCoordinate(dim1, Rational.ONE); - s0.AddCoordinate(dim2, Rational.FromInts(1, 2)); - s0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); - - FrameElement s1 = new FrameElement(); - s1.AddCoordinate(dim1, Rational.ONE); - s1.AddCoordinate(dim2, Rational.FromInts(-1, 2)); - s1.AddCoordinate(dim3, Rational.FromInts(1, 2)); - - FrameElement s2 = new FrameElement(); - s2.AddCoordinate(dim1, Rational.FromInt(3)); - s2.AddCoordinate(dim2, Rational.FromInts(-3, 2)); - s2.AddCoordinate(dim3, Rational.FromInts(3, 2)); - - FrameElement r0 = new FrameElement(); - r0.AddCoordinate(dim1, Rational.ONE); - r0.AddCoordinate(dim2, Rational.FromInts(1, 2)); - r0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); - - FrameElement r1 = new FrameElement(); - r1.AddCoordinate(dim1, Rational.ONE); - r1.AddCoordinate(dim2, Rational.ZERO); - r1.AddCoordinate(dim3, Rational.ZERO); - - FrameElement d0 = new FrameElement(); - d0.AddCoordinate(dim1, Rational.ZERO); - d0.AddCoordinate(dim2, Rational.ONE); - d0.AddCoordinate(dim3, Rational.ONE); - - LinearConstraintSystem lcs = new LinearConstraintSystem(s0); - lcs.Dump(); - - lcs.AddVertex(s1); - lcs.Dump(); - - lcs.AddVertex(s2); - lcs.Dump(); - - lcs.AddRay(r0); - lcs.Dump(); - - lcs.AddRay(r1); - lcs.Dump(); - - lcs.AddLine(d0); - lcs.Dump(); - - lcs.SimplifyConstraints(); - lcs.Dump(); - -#if LATER - lcs.GenerateFrameFromConstraints(); // should give us back the original frame... -#endif - } - } +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System; + //using Microsoft.SpecSharp.Collections; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using IMutableSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + /// + /// Represents a system of linear constraints (constraint/frame representations). + /// + public class LinearConstraintSystem { + // -------------------------------------------------------------------------------------------------------- + // ------------------ Data structure ---------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public /*maybe null*/ ArrayList /*LinearConstraint!*/ Constraints; + /*maybe null*/ + ArrayList /*FrameElement!*/ FrameVertices; + /*maybe null*/ + ArrayList /*FrameElement!*/ FrameRays; + IMutableSet/*IVariable!*//*!*/ FrameDimensions; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(FrameDimensions != null); + } + + /*maybe null*/ + ArrayList /*FrameElement!*/ FrameLines; + // Invariant: Either all of Constraints, FrameVertices, FrameRays, and FrameLines are + // null, or all are non-null. + // Invariant: Any dimension mentioned in Constraints, FrameVertices, FrameRays, or + // FrameLines is mentioned in FrameDimensions. + // The meaning of FrameDimensions is that for any dimension x not in FrameDimensions, + // there is an implicit line along dimension x (that is, ()). + + void CheckInvariant() { + if (Constraints == null) { + System.Diagnostics.Debug.Assert(FrameVertices == null); + System.Diagnostics.Debug.Assert(FrameRays == null); + System.Diagnostics.Debug.Assert(FrameLines == null); + System.Diagnostics.Debug.Assert(FrameDimensions.Count == 0); + } else { + System.Diagnostics.Debug.Assert(FrameVertices != null); + System.Diagnostics.Debug.Assert(FrameRays != null); + System.Diagnostics.Debug.Assert(FrameLines != null); + + foreach (LinearConstraint/*!*/ cc in Constraints) { + Contract.Assert(cc != null); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(cc.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + Contract.Assert(cc.coefficients.Count != 0); + } + foreach (ArrayList /*FrameElement*//*!*/ FrameComponent in new ArrayList /*FrameElement*/ [] { FrameVertices, FrameRays, FrameLines }) { + Contract.Assert(FrameComponent != null); + foreach (FrameElement fe in FrameComponent) { + if (fe == null) + continue; +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(fe.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + } + } + } + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Constructors ------------------------------------------------------------------------ + // -------------------------------------------------------------------------------------------------------- + + /// + /// Creates a LinearConstraintSystem representing the bottom element, that is, representing + /// an unsatisfiable system of constraints. + /// + [NotDelayed] + public LinearConstraintSystem() { + FrameDimensions = new HashSet /*IVariable!*/ (); + //:base(); + CheckInvariant(); + } + + /// + /// Constructs a linear constraint system with constraints "cs". + /// The constructor captures all constraints in "cs". + /// + /// + [NotDelayed] + public LinearConstraintSystem(ArrayList /*LinearConstraint!*//*!*/ cs) { + Contract.Requires(cs != null); +#if BUG_159_HAS_BEEN_FIXED + Contract.Requires(Contract.ForAll(cs) , cc=> cc.coefficients.Count != 0); +#endif + + ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count); + foreach (LinearConstraint/*!*/ cc in cs) { + Contract.Assert(cc != null); + constraints.Add(cc); + } + Constraints = constraints; + FrameDimensions = new HashSet /*IVariable!*/ (); // to please compiler; this value will be overridden in the call to GenerateFrameConstraints below + //:base(); + + GenerateFrameFromConstraints(); + SimplifyConstraints(); + CheckInvariant(); +#if DEBUG_PRINT + Console.WriteLine("LinearConstraintSystem: constructor produced:"); + Dump(); +#endif + } + + /// + /// Constructs a linear constraint system corresponding to given vertex. This constructor + /// is only used in the test harness--it is not needed for abstract interpretation. + /// + /// + [NotDelayed] + LinearConstraintSystem(FrameElement/*!*/ v) { + Contract.Requires(v != null); + IMutableSet/*!*/ frameDims = v.GetDefinedDimensions(); + Contract.Assert(frameDims != null); + ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ (); + foreach (IVariable/*!*/ dim in frameDims) { + Contract.Assert(dim != null); + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + lc.SetCoefficient(dim, Rational.ONE); + lc.rhs = v[dim]; + constraints.Add(lc); + } + FrameDimensions = frameDims; + Constraints = constraints; + + ArrayList /*FrameElement*/ frameVertices = new ArrayList /*FrameElement*/ (); + frameVertices.Add(v); + FrameVertices = frameVertices; + + FrameRays = new ArrayList /*FrameElement*/ (); + FrameLines = new ArrayList /*FrameElement*/ (); + + //:base(); + CheckInvariant(); + } + + void ChangeIntoBottom() { + Constraints = null; + FrameVertices = null; + FrameRays = null; + FrameLines = null; + FrameDimensions.Clear(); // no implicit lines + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Public operations and their support routines ---------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public bool IsBottom() { + return Constraints == null; + } + + public bool IsTop() { + return Constraints != null && Constraints.Count == 0; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + if (Constraints == null) { + return ""; + } else if (Constraints.Count == 0) { + return ""; + } else { + string z = null; + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + string s = lc.ToString(); + if (z == null) { + z = s; + } else { + z += " AND " + s; + } + } + Contract.Assert(z != null); + return z; + } + } + + + public ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + List list = new List(); + foreach (IVariable/*!*/ v in FrameDimensions) { + Contract.Assert(v != null); + list.Add(v); + } + return cce.NonNull(list.AsReadOnly()); + } + + /// + /// Note: This method requires that all dimensions are of type Variable, something that's + /// not required elsewhere in this class. + /// + /// + public IExpr/*!*/ ConvertToExpression(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result() != null); + if (this.Constraints == null) { + return factory.False; + } + if (this.Constraints.Count == 0) { + return factory.True; + } + + IExpr result = null; + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + IExpr conjunct = lc.ConvertToExpression(factory); + result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result); + } + Contract.Assert(result != null); + return result; + } + + + /* IsSubset(): determines if 'lcs' is a subset of 'this' + * -- See Cousot/Halbwachs 1978, section + */ + public bool IsSubset(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + if (lcs.IsBottom()) { + return true; + } else if (this.IsBottom()) { + return false; +#if DEBUG +#else + } else if (this.IsTop()) { // optimization -- this case not needed for correctness + return true; + } else if (lcs.IsTop()) { // optimization -- this case not needed for correctness + return false; +#endif + } else { + // phase 0: check if frame dimensions are a superset of the constraint dimensions + ISet /*IVariable!*//*!*/ frameDims = lcs.GetDefinedDimensions(); + Contract.Assert(frameDims != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: IsSubset:"); + Console.WriteLine(" --- this:"); + this.Dump(); + Console.WriteLine(" --- lcs:"); + lcs.Dump(); + Console.WriteLine(" ---"); +#endif + foreach (LinearConstraint/*!*/ cc in cce.NonNull(this.Constraints)) { + Contract.Assert(cc != null); +#if DEBUG_PRINT + Console.WriteLine(" cc: {0}", cc); + Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions()); +#endif + + if (!Contract.ForAll(cc.GetDefinedDimensionsGeneric(), var => frameDims.Contains(var))) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 0 subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + + // phase 1: check frame vertices against each constraint... + foreach (FrameElement/*!*/ v in cce.NonNull(lcs.FrameVertices)) { + Contract.Assert(v != null); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + Rational q = cc.EvaluateLhs(v); + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + if (!(q <= cc.rhs)) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 1a subset violated, return false from IsSubset"); +#endif + return false; + } + } else { + if (!(q == cc.rhs)) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 1b subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + } + + // phase 2: check frame rays against each constraint... + // To check if a ray "r" falls within a constraint "cc", we add the vector "r" to + // any point "p" on the side of the half-space or plane described by constraint, and + // then check if the resulting point satisfies the constraint. That is, we check (for + // an inequality constraint with coefficients a1,a2,...,an and right-hand side + // constant C): + // a1*(r1+p1) + a2*(r2+p2) + ... + an*(rn+pn) <= C + // Equivalently: + // a1*r1 + a2*r2 + ... + an*rn + a1*p1 + a2*p2 + ... + an*pn <= C + // To find a point "p", we can pick out a coordinate, call it 1, with a non-zero + // coefficient in the constraint, and then choose "p" as the point that has the + // value C/a1 in coordinate 1 and has 0 in all other coordinates. We then check: + // a1*r1 + a2*r2 + ... + an*rn + a1*(C/a1) + a2*0 + ... + an*0 <= C + // which simplifies to: + // a1*r1 + a2*r2 + ... + an*rn + C <= C + // which in turn simplifies to: + // a1*r1 + a2*r2 + ... + an*rn <= 0 + // If the constraint is an equality constraint, we simply replace "<=" with "==" + // above. + foreach (FrameElement/*!*/ r in cce.NonNull(lcs.FrameRays)) { + Contract.Assert(r != null); + System.Diagnostics.Debug.Assert(r != null, "encountered a null ray..."); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); + Rational q = cc.EvaluateLhs(r); + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + if (q.IsPositive) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 2a subset violated, return false from IsSubset"); +#endif + return false; + } + } else { + if (q.IsNonZero) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 2b subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + } + + // phase 3: check frame lines against each constraint... + // To check if a line "L" falls within a constraint "cc", we check if both the + // vector "L" and "-L", interpreted as rays, fall within the constraint. From + // the discussion above, this means we check the following two properties: + // a1*L1 + a2*L2 + ... + an*Ln <= 0 (*) + // a1*(-L1) + a2*(-L2) + ... + an*(-Ln) <= 0 + // The second of these lines can be rewritten as: + // - a1*L1 - a2*L2 - ... - an*Ln <= 0 + // which is equivalent to: + // -1 * (a1*L1 + a2*L2 + ... + an*Ln) <= 0 + // Multiplying both sides by -1 and flipping the direction of the inequality, + // we have: + // a1*L1 + a2*L2 + ... + an*Ln >= 0 (**) + // Putting (*) and (**) together, we conclude that we need to check: + // a1*L1 + a2*L2 + ... + an*Ln == 0 + // If the constraint is an equality constraint, we end up with the same equation. + foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { + Contract.Assert(line != null); + System.Diagnostics.Debug.Assert(line != null, "encountered a null line..."); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint..."); + Rational q = cc.EvaluateLhs(line); + if (q.IsNonZero) { +#if DEBUG_PRINT + Console.WriteLine(" ---> phase 3 subset violated, return false from IsSubset"); +#endif + return false; + } + } + } + +#if DEBUG_PRINT + Console.WriteLine(" ---> IsSubset returns true"); +#endif + return true; + } + + public LinearConstraintSystem/*!*/ Meet(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + Contract.Requires((this.Constraints != null)); + Contract.Requires((lcs.Constraints != null)); + Contract.Ensures(Contract.Result() != null); + ArrayList /*LinearConstraint*/ clist = new ArrayList(this.Constraints.Count + lcs.Constraints.Count); + clist.AddRange(this.Constraints); + clist.AddRange(lcs.Constraints); + return new LinearConstraintSystem(clist); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Join(LinearConstraintSystem lcs) + { + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Join"); + Console.WriteLine("Join: this="); + Dump(); + Console.WriteLine("Join: lcs="); + lcs.Dump(); + LinearConstraintSystem z = JoinX(lcs); + Console.WriteLine("----------Join------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Join: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + + /// + /// The join is computed as described in section 4.4 in Cousot and Halbwachs. + /// + /// + /// +#if DEBUG_PRINT + public LinearConstraintSystem JoinX(LinearConstraintSystem lcs) { +#else + public LinearConstraintSystem/*!*/ Join(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + Contract.Ensures(Contract.Result() != null); +#endif + + if (this.IsBottom()) { + return cce.NonNull(lcs.Clone()); + } else if (lcs.IsBottom()) { + return cce.NonNull(this.Clone()); + } else if (this.IsTop() || lcs.IsTop()) { + return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); + } else { + LinearConstraintSystem/*!*/ z; + // Start from the "larger" of the two frames (this is just a heuristic measure intended + // to save work). + Contract.Assume(this.FrameVertices != null); + Contract.Assume(this.FrameRays != null); + Contract.Assume(this.FrameLines != null); + Contract.Assume(lcs.FrameVertices != null); + Contract.Assume(lcs.FrameRays != null); + Contract.Assume(lcs.FrameLines != null); + if (this.FrameVertices.Count + this.FrameRays.Count + this.FrameLines.Count - this.FrameDimensions.Count < + lcs.FrameVertices.Count + lcs.FrameRays.Count + lcs.FrameLines.Count - lcs.FrameDimensions.Count) { + z = cce.NonNull(lcs.Clone()); + lcs = this; + } else { + z = cce.NonNull(this.Clone()); + } +#if DEBUG_PRINT + Console.WriteLine("DEBUG: LinearConstraintSystem.Join ---------------"); + Console.WriteLine("z:"); + z.Dump(); + Console.WriteLine("lcs:"); + lcs.Dump(); +#endif + + // Start by explicating the implicit lines of z for the dimensions dims(lcs)-dims(z). + foreach (IVariable/*!*/ dim in lcs.FrameDimensions) { + Contract.Assert(dim != null); + if (!z.FrameDimensions.Contains(dim)) { + z.FrameDimensions.Add(dim); + FrameElement line = new FrameElement(); + line.AddCoordinate(dim, Rational.ONE); + // Note: AddLine is not called (because the line already exists in z--it's just that + // it was represented implicitly). Instead, just tack the explicit representation onto + // FrameLines. + Contract.Assume(z.FrameLines != null); + z.FrameLines.Add(line); +#if DEBUG_PRINT + Console.WriteLine("Join: After explicating line: {0}", line); + z.Dump(); +#endif + } + } + + // Now, the vertices, rays, and lines can be added. + foreach (FrameElement/*!*/ v in lcs.FrameVertices) { + Contract.Assert(v != null); + z.AddVertex(v); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding vertex: {0}", v); + z.Dump(); +#endif + } + foreach (FrameElement/*!*/ r in lcs.FrameRays) { + Contract.Assert(r != null); + z.AddRay(r); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding ray: {0}", r); + z.Dump(); +#endif + } + foreach (FrameElement/*!*/ l in lcs.FrameLines) { + Contract.Assert(l != null); + z.AddLine(l); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding line: {0}", l); + z.Dump(); +#endif + } + // also add to z the implicit lines of lcs + foreach (IVariable/*!*/ dim in z.FrameDimensions) { + Contract.Assert(dim != null); + if (!lcs.FrameDimensions.Contains(dim)) { + // "dim" is a dimension that's explicit in "z" but implicit in "lcs" + FrameElement line = new FrameElement(); + line.AddCoordinate(dim, Rational.ONE); + z.AddLine(line); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding lcs's implicit line: {0}", line); + z.Dump(); +#endif + } + } + + z.SimplifyFrame(); + z.SimplifyConstraints(); + z.CheckInvariant(); +#if DEBUG_PRINT + Console.WriteLine("Join: Returning z:"); + z.Dump(); + Console.WriteLine("----------------------------------------"); +#endif + return z; + } + } + +#if DEBUG_PRINT + public LinearConstraintSystem Widen(LinearConstraintSystem lcs) + { + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Widen"); + Console.WriteLine("Widen: this="); + Dump(); + Console.WriteLine("Widen: lcs="); + lcs.Dump(); + LinearConstraintSystem z = WidenX(lcs); + Console.WriteLine("----------Widen------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Widen: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + +#if DEBUG_PRINT + public LinearConstraintSystem WidenX(LinearConstraintSystem lcs){ +#else + public LinearConstraintSystem/*!*/ Widen(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + Contract.Ensures(Contract.Result() != null); +#endif + if (this.IsBottom()) { + return cce.NonNull(lcs.Clone()); + } else if (lcs.IsBottom()) { + return cce.NonNull(this.Clone()); + } else if (this.IsTop() || lcs.IsTop()) { + return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); + } + + // create new LCS, we will add only verified constraints to this... + ArrayList /*LinearConstraint*/ newConstraints = new ArrayList /*LinearConstraint*/ (); + Contract.Assume(this.Constraints != null); + foreach (LinearConstraint/*!*/ ccX in this.Constraints) { + Contract.Assert(ccX != null); + LinearConstraint cc = ccX; +#if DEBUG_PRINT + Console.WriteLine("Widen checking: Starting to check constraint: {0}", cc); +#endif + if (cc.IsConstant()) { + // (Can this ever occur in the stable state of a LinearConstraintSystem? --KRML) + // constraint is unaffected by the frame components +#if DEBUG_PRINT + Console.WriteLine("Widen checking: --Adding it!"); +#endif + newConstraints.Add(cc); + continue; + } + + // PHASE I: verify constraints against all frame vertices... + + foreach (FrameElement/*!*/ vertex in cce.NonNull(lcs.FrameVertices)) { + Contract.Assert(vertex != null); + Rational lhs = cc.EvaluateLhs(vertex); + if (lhs > cc.rhs) { + // the vertex does not satisfy the inequality <= + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out because of vertex: {0}", vertex); +#endif + goto CHECK_NEXT_CONSTRAINT; + } else { + // ... but it does satisfy the inequality >= +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out <= because of vertex: {0}", vertex); +#endif + cc = cc.ChangeRelationToAtLeast(); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with constraint: {0}", cc); +#endif + } + } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs < cc.rhs) { + // the vertex does not satisfy the inequality >=, and the constraint is an equality constraint +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out >= because of vertex: {0}", vertex); +#endif + cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with contraint: {0}", cc); +#endif + } + } + + // PHASE II: verify constraints against all frame rays... + + foreach (FrameElement/*!*/ ray in cce.NonNull(lcs.FrameRays)) { + Contract.Assert(ray != null); + // The following assumes the constraint to have some dimension with a non-zero coefficient + Rational lhs = cc.EvaluateLhs(ray); + if (lhs.IsPositive) { + // the ray does not satisfy the inequality <= + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out because of ray: {0}", ray); +#endif + goto CHECK_NEXT_CONSTRAINT; + } else { + // ... but it does satisfy the inequality >= +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out <= because of ray: {0}", ray); +#endif + cc = cc.ChangeRelationToAtLeast(); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with contraint: {0}", cc); +#endif + } + } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs.IsNegative) { + // the ray does not satisfy the inequality >=, and the constraint is an equality constraint +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out >= because of ray: {0}", ray); +#endif + cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE); +#if DEBUG_PRINT + Console.WriteLine("Widen checking: left with constraint: {0}", cc); +#endif + } + } + + // PHASE III: verify constraints against all frame lines... + + foreach (FrameElement/*!*/ line in cce.NonNull(lcs.FrameLines)) { + Contract.Assert(line != null); + // The following assumes the constraint to have some dimension with a non-zero coefficient + Rational lhs = cc.EvaluateLhs(line); + if (!lhs.IsZero) { + // The line satisfies neither the inequality <= nor the equality == +#if DEBUG_PRINT + Console.WriteLine("Widen checking: throwing out because of line: {0}", line); +#endif + goto CHECK_NEXT_CONSTRAINT; + } + } + + // constraint has been verified, so add to new constraint system +#if DEBUG_PRINT + Console.WriteLine("Widen checking: --Adding it!"); +#endif + newConstraints.Add(cc); + + CHECK_NEXT_CONSTRAINT: { + } +#if DEBUG_PRINT + Console.WriteLine("Widen checking: done with that constraint"); +#endif + } + + return new LinearConstraintSystem(newConstraints); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Project(IVariable/*!*/ dim){ +Contract.Requires(dim != null); + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Project(dim={0})", dim); + Console.WriteLine("Project: this="); + Dump(); + LinearConstraintSystem z = ProjectX(dim); + Console.WriteLine("----------Project------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Project: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + +#if DEBUG_PRINT + public LinearConstraintSystem ProjectX(IVariable/*!*/ dim){Contract.Requires(dim != null);Contract.Requires(this.Constraints != null); +#else + public LinearConstraintSystem/*!*/ Project(IVariable/*!*/ dim) { + Contract.Requires(dim != null); + Contract.Requires(this.Constraints != null); + Contract.Ensures(Contract.Result() != null); +#endif + + + ArrayList /*LinearConstraint!*//*!*/ cc = Project(dim, Constraints); + Contract.Assert(cc != null); + return new LinearConstraintSystem(cc); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName){ +Contract.Requires(newName != null); +Contract.Requires(oldName != null); + Console.WriteLine("==================================================================================="); + Console.WriteLine("DEBUG: Rename(oldName={0}, newName={1})", oldName, newName); + Console.WriteLine("Rename: this="); + Dump(); + LinearConstraintSystem z = RenameX(oldName, newName); + Console.WriteLine("----------Rename------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + Console.WriteLine("Rename: result="); + z.Dump(); + Console.WriteLine("==================================================================================="); + return z; + } +#endif + +#if DEBUG_PRINT + public LinearConstraintSystem RenameX(IVariable/*!*/ oldName, IVariable/*!*/ newName){Contract.Requires(oldName != null);Contract.Requires(newName != null); +#else + public LinearConstraintSystem/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(oldName != null); + Contract.Requires(newName != null); + Contract.Ensures(Contract.Result() != null); +#endif + if (this.Constraints == null) { + System.Diagnostics.Debug.Assert(this.FrameVertices == null); + System.Diagnostics.Debug.Assert(this.FrameRays == null); + System.Diagnostics.Debug.Assert(this.FrameLines == null); + return this; + } + IMutableSet /*IVariable!*//*!*/ dims = this.FrameDimensions; + Contract.Assert(dims != null); + if (!dims.Contains(oldName)) { + return this; + } + + LinearConstraintSystem z = new LinearConstraintSystem(); + z.FrameDimensions = cce.NonNull((HashSet/*!*/ /*IVariable!*/)dims.Clone()); + z.FrameDimensions.Remove(oldName); + z.FrameDimensions.Add(newName); + + z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count); + foreach (LinearConstraint/*!*/ lc in cce.NonNull(this.Constraints)) { + Contract.Assert(lc != null); + z.Constraints.Add(lc.Rename(oldName, newName)); + } + z.FrameVertices = RenameInFE(cce.NonNull(this.FrameVertices), oldName, newName); + z.FrameRays = RenameInFE(cce.NonNull(this.FrameRays), oldName, newName); + z.FrameLines = RenameInFE(cce.NonNull(this.FrameLines), oldName, newName); + return z; + } + + static ArrayList /*FrameElement*/ RenameInFE(ArrayList/*!*/ /*FrameElement*/ list, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(list != null); + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + ArrayList/*FrameElement!*//*!*/ z = new ArrayList/*FrameElement!*/ (list.Count); + Contract.Assert(z != null); + foreach (FrameElement/*!*/ fe in list) { + Contract.Assert(fe != null); + z.Add(fe.Rename(oldName, newName)); + } + System.Diagnostics.Debug.Assert(z.Count == list.Count); + return z; + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ support routines -------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + /// + /// Returns a set of constraints that is the given set of constraints with dimension "dim" + /// projected out. See Cousot and Halbwachs, section 3.3.1.1. + /// + /// + /// + /// + static ArrayList /*LinearConstraint!*//*!*/ Project(IVariable/*!*/ dim, ArrayList /*LinearConstraint!*//*!*/ constraints) { + Contract.Requires(constraints != null); + Contract.Requires(dim != null); + Contract.Ensures(Contract.Result() != null); + // Sort the inequality constaints into ones where dimension "dim" is 0, negative, and + // positive, respectively. Put equality constraints with a non-0 "dim" into "eq". + ArrayList /*LinearConstraint!*//*!*/ final = new ArrayList /*LinearConstraint!*/ (); + ArrayList /*LinearConstraint!*//*!*/ negative = new ArrayList /*LinearConstraint!*/ (); + ArrayList /*LinearConstraint!*//*!*/ positive = new ArrayList /*LinearConstraint!*/ (); + ArrayList /*LinearConstraint!*//*!*/ eq = new ArrayList /*LinearConstraint!*/ (); + foreach (LinearConstraint/*!*/ cc in constraints) { + Contract.Assert(cc != null); + Rational coeff = cc[dim]; + if (coeff.IsZero) { + LinearConstraint lc = cce.NonNull(cc.Clone()); + if (!lc.IsConstant()) { + lc.RemoveDimension(dim); + final.Add(lc); + } + } else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ) { + eq.Add(cc); + } else if (coeff.IsNegative) { + negative.Add(cc); + } else { + System.Diagnostics.Debug.Assert(coeff.IsPositive); + positive.Add(cc); + } + } + + if (eq.Count != 0) { + LinearConstraint eqConstraint = (LinearConstraint/*!*/)cce.NonNull(eq[eq.Count - 1]); + eq.RemoveAt(eq.Count - 1); + Rational eqC = -eqConstraint[dim]; + + foreach (ArrayList /*LinearConstraint!*/ list in new ArrayList[] { eq, negative, positive }) { + Contract.Assert(list != null); + foreach (LinearConstraint/*!*/ lcX in list) { + Contract.Assert(lcX != null); + LinearConstraint lc = cce.NonNull(lcX.Clone()); + lc.AddMultiple(lc[dim] / eqC, eqConstraint); + System.Diagnostics.Debug.Assert(lc[dim].IsZero); + if (!lc.IsConstant()) { + lc.RemoveDimension(dim); + final.Add(lc); + } else { + System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); + } + } + } + } else { + // Consider all pairs of constraints with (negative,positive) coefficients of "dim". + foreach (LinearConstraint/*!*/ cn in negative) { + Contract.Assert(cn != null); + Rational dn = -cn[dim]; + System.Diagnostics.Debug.Assert(dn.IsNonNegative); + foreach (LinearConstraint/*!*/ cp in positive) { + Contract.Assert(cp != null); + Rational dp = cp[dim]; + + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + lc.AddMultiple(dn, cp); + lc.AddMultiple(dp, cn); + System.Diagnostics.Debug.Assert(lc[dim].IsZero); + if (!lc.IsConstant()) { + lc.RemoveDimension(dim); + final.Add(lc); + } else { + System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable()); + } + } + } + } + + return final; + } + + /// + /// Initializes FrameVertices, FrameRays, FrameLines, and FrameDimensions, see + /// Cousot and Halbwachs, section 3.4. Any previous values of these fields are + /// ignored and overwritten. + /// + /// If the set of Constraints is unsatisfiable, then "this" is changed into Bottom. + /// + void GenerateFrameFromConstraints() { + if (Constraints == null) { + FrameVertices = null; + FrameRays = null; + FrameLines = null; + FrameDimensions = new HashSet /*IVariable!*/ (); + return; + } + + // Step 1 (see Cousot and Halbwachs, section 3.4.3): create a Simplex Tableau. +#if DEBUG_PRINT + Console.WriteLine("DEBUG: --- GenerateFrameFromConstraint ---"); + Console.WriteLine("Constraints:"); + foreach (LinearConstraint cc in Constraints) + { + Console.WriteLine(" {0}", cc); + } +#endif + SimplexTableau tableau = new SimplexTableau(Constraints); +#if DEBUG_PRINT + Console.WriteLine("Initial tableau:"); + tableau.Dump(); +#endif + FrameDimensions = tableau.GetDimensions(); +#if DEBUG_PRINT + Console.WriteLine("Dimensions:"); + foreach (object dim in FrameDimensions) + { + Console.Write(" {0}", dim); + } + Console.WriteLine(); +#endif + + // Step 3 and 2: Put as many initial variables as possible into basis, then check if + // we reached a feasible basis + tableau.AddInitialVarsToBasis(); +#if DEBUG_PRINT + Console.WriteLine("Tableau after Step 3:"); + tableau.Dump(); +#endif + if (!tableau.IsFeasibleBasis) { + // The polyhedron is empty (according to Cousot and Halbwachs) + ChangeIntoBottom(); + return; + } + + FrameVertices = new ArrayList /*FrameElement*/ (); + FrameRays = new ArrayList /*FrameElement*/ (); + FrameLines = new ArrayList /*FrameElement*/ (); + if (FrameDimensions.Count == 0) { + // top element + return; + } + + if (tableau.AllInitialVarsInBasis) { + // All initial variables are in basis; there are no lines. +#if DEBUG_PRINT + Console.WriteLine("Tableau after Steps 2 and 3 (all initial variables in basis):"); + tableau.Dump(); +#endif + } else { + // There are lines +#if DEBUG_PRINT + Console.WriteLine("Tableau after Steps 2 and 3 (NOT all initial variables in basis--there are lines):"); + tableau.Dump(); +#endif + // Step 4.2: Pick out the lines, then produce the tableau for a new polyhedron without those lines. + ArrayList /*LinearConstraint*/ moreConstraints = cce.NonNull((ArrayList/*!*/ /*LinearConstraint*/)Constraints.Clone()); + tableau.ProduceLines(FrameLines, moreConstraints); + tableau = new SimplexTableau(moreConstraints); +#if DEBUG_PRINT + Console.WriteLine("Lines produced:"); + foreach (FrameElement line in FrameLines) + { + Console.WriteLine(" {0}", line); + } + Console.WriteLine("The new list of constraints is:"); + foreach (LinearConstraint c in moreConstraints) + { + Console.WriteLine(" {0}", c); + } + Console.WriteLine("Tableau after producing lines in Step 4.2:"); + tableau.Dump(); +#endif + + // Repeat step 3 for the new tableau. + // Since the new tableau contains no lines, the following call should cause all initial + // variables to be in basis (see step 4.2 in section 3.4.3 of Cousot and Halbwachs). + tableau.AddInitialVarsToBasis(); + System.Diagnostics.Debug.Assert(tableau.AllInitialVarsInBasis); + System.Diagnostics.Debug.Assert(tableau.IsFeasibleBasis); // the new tableau represents a set of feasible constraints, so this basis should be found to be feasible +#if DEBUG_PRINT + Console.WriteLine("Tableau after all initial variables have been moved into basis:"); + tableau.Dump(); +#endif + } + + // Step 4.1: One vertex has been found. Find all others, too. + tableau.TraverseVertices(FrameVertices, FrameRays); +#if DEBUG_PRINT + Console.WriteLine("Tableau after vertex traversal:"); + tableau.Dump(); +#endif + } + + class LambdaDimension : IVariable { + readonly int id; + static int count = 0; + + /// + /// Return the name of the variable + /// + public string Name { + get { + Contract.Ensures(Contract.Result() != null); + + return this.ToString(); + } + } + + public LambdaDimension() { + id = count; + count++; + } + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "lambda" + id; + } + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitVariable(this); + } + } + + /// + /// Adds a vertex to the frame of "this" and updates Constraints accordingly, see + /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify + /// Constraints after the operation; that remains the caller's responsibility (which + /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, + /// and AddLine before calling SimplifyConstraints). + /// Assumes Constraints (and the frame fields) to be non-null. + /// + /// + void AddVertex(FrameElement/*!*/ vertex) { + Contract.Requires(vertex != null); + Contract.Requires(this.FrameVertices != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: AddVertex called on {0}", vertex); + Console.WriteLine(" Initial constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + FrameVertices.Add(vertex.Clone()); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(vertex.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + + // We use a new temporary dimension. + IVariable/*!*/ lambda = new LambdaDimension(); + + // We change the constraints A*X <= B into + // A*X + (A*vector - B)*lambda <= A*vector. + // That means that each row k in A (which corresponds to one LinearConstraint + // in Constraints) is changed by adding + // (A*vector - B)[k] * lambda + // to row k and changing the right-hand side of row k to + // (A*vector)[k] + // Note: + // (A*vector - B)[k] + // = { vector subtraction is pointwise } + // (A*vector)[k] - B[k] + // = { A*vector is a row vector whose every row i is the dot-product of + // row i of A with the column vector "vector" } + // A[k]*vector - B[k] + foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + Rational d = cc.EvaluateLhs(vertex); + cc.SetCoefficient(lambda, d - cc.rhs); + cc.rhs = d; + } + + // We also add the constraints that lambda lies between 0 ... + LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + la.SetCoefficient(lambda, Rational.MINUS_ONE); + la.rhs = Rational.ZERO; + Constraints.Add(la); + // ... and 1. + la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + la.SetCoefficient(lambda, Rational.ONE); + la.rhs = Rational.ONE; + Constraints.Add(la); +#if DEBUG_PRINT + Console.WriteLine(" Constraints after addition:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + // Finally, project out the dummy dimension. + Constraints = Project(lambda, Constraints); + +#if DEBUG_PRINT + Console.WriteLine(" Resulting constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + } + + /// + /// Adds a ray to the frame of "this" and updates Constraints accordingly, see + /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify + /// Constraints after the operation; that remains the caller's responsibility (which + /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, + /// and AddLine before calling SimplifyConstraints). + /// Assumes Constraints (and the frame fields) to be non-null. + /// + /// + void AddRay(FrameElement/*!*/ ray) { + Contract.Requires(ray != null); + Contract.Requires(this.FrameRays != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: AddRay called on {0}", ray); + Console.WriteLine(" Initial constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + FrameRays.Add(ray.Clone()); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(ray.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + + // We use a new temporary dimension. + IVariable/*!*/ lambda = new LambdaDimension(); + + // We change the constraints A*X <= B into + // A*X - (A*ray)*lambda <= B. + // That means that each row k in A (which corresponds to one LinearConstraint + // in Constraints) is changed by subtracting + // (A*ray)[k] * lambda + // from row k. + // Note: + // (A*ray)[k] + // = { A*ray is a row vector whose every row i is the dot-product of + // row i of A with the column vector "ray" } + // A[k]*ray + foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + Rational d = cc.EvaluateLhs(ray); + cc.SetCoefficient(lambda, -d); + } + + // We also add the constraints that lambda is at least 0. + LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + la.SetCoefficient(lambda, Rational.MINUS_ONE); + la.rhs = Rational.ZERO; + Constraints.Add(la); +#if DEBUG_PRINT + Console.WriteLine(" Constraints after addition:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + // Finally, project out the dummy dimension. + Constraints = Project(lambda, Constraints); + +#if DEBUG_PRINT + Console.WriteLine(" Resulting constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + } + + /// + /// Adds a line to the frame of "this" and updates Constraints accordingly, see + /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify + /// Constraints after the operation; that remains the caller's responsibility (which + /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay, + /// and AddLine before calling SimplifyConstraints). + /// Assumes Constraints (and the frame fields) to be non-null. + /// + /// + void AddLine(FrameElement/*!*/ line) { + Contract.Requires(line != null); + Contract.Requires(this.FrameLines != null); + // Note: The code for AddLine is identical to that of AddRay, except the AddLine + // does not introduce the constraint 0 <= lambda. (One could imagine sharing the + // code between AddRay and AddLine.) +#if DEBUG_PRINT + Console.WriteLine("DEBUG: AddLine called on {0}", line); + Console.WriteLine(" Initial constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + FrameLines.Add(line.Clone()); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(line.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + + // We use a new temporary dimension. + IVariable/*!*/ lambda = new LambdaDimension(); + + // We change the constraints A*X <= B into + // A*X - (A*line)*lambda <= B. + // That means that each row k in A (which corresponds to one LinearConstraint + // in Constraints) is changed by subtracting + // (A*line)[k] * lambda + // from row k. + // Note: + // (A*line)[k] + // = { A*line is a row vector whose every row i is the dot-product of + // row i of A with the column vector "line" } + // A[k]*line + foreach (LinearConstraint/*!*/ cc in cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + Rational d = cc.EvaluateLhs(line); + cc.SetCoefficient(lambda, -d); + } + +#if DEBUG_PRINT + Console.WriteLine(" Constraints after addition:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + + // Finally, project out the dummy dimension. + Constraints = Project(lambda, Constraints); + +#if DEBUG_PRINT + Console.WriteLine(" Resulting constraints:"); + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } +#endif + } + + ISet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); + foreach (ArrayList p in new ArrayList[] { FrameVertices, FrameRays, FrameLines }) { + if (p != null) { + foreach (FrameElement/*!*/ element in p) { + Contract.Assert(element != null); + foreach (IVariable/*!*/ dim in element.GetDefinedDimensions()) { + Contract.Assert(dim != null); + dims.Add(dim); + } + } + } + } + return dims; + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Simplification routines ------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + /// + /// Uses the Constraints to simplify the frame. See section 3.4.4 of Cousot and Halbwachs. + /// + void SimplifyFrame() { + Contract.Requires(this.Constraints != null); + SimplificationStatus[]/*!*/ status; + + SimplifyFrameElements(cce.NonNull(FrameVertices), true, Constraints, out status); + RemoveIrrelevantFrameElements(FrameVertices, status, null); + + SimplifyFrameElements(cce.NonNull(FrameRays), false, Constraints, out status); + RemoveIrrelevantFrameElements(FrameRays, status, FrameLines); + } + + enum SimplificationStatus { + Irrelevant, + Relevant, + More + }; + + /// + /// For each i, sets status[i] to: + ///
    + ///
  • Irrelevant if ff[i] is irrelevant
  • + ///
  • Relevant if ff[i] is irrelevant
  • + ///
  • More if vertices is true and ray ff[i] can be replaced by a line ff[i]
  • + ///
+ ///
+ /// + /// true if "ff" contains vertices; false if "ff" contains rays + /// + /// + static void SimplifyFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, bool vertices, ArrayList/*!*/ /*LinearConstraint*/ constraints, out SimplificationStatus[]/*!*/ status) { + Contract.Requires(ff != null); + Contract.Requires(constraints != null); + Contract.Ensures(Contract.ValueAtReturn(out status) != null); + status = new SimplificationStatus[ff.Count]; + bool[,] sat = new bool[ff.Count, constraints.Count]; + for (int i = 0; i < ff.Count; i++) { + FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]); + int cnt = 0; + for (int c = 0; c < constraints.Count; c++) { + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(constraints[c]); + bool s = lc.IsSaturatedBy(f, vertices); + if (s) { + sat[i, c] = true; + cnt++; + } + } + if (!vertices && cnt == constraints.Count) { + status[i] = SimplificationStatus.More; + } else { + status[i] = SimplificationStatus.Relevant; + } + } + + CheckPairSimplifications(sat, status); + } + + /// + /// Requires sat.GetLength(0) == status.Length. + /// + /// + /// + static void CheckPairSimplifications(bool[,]/*!*/ sat, SimplificationStatus[]/*!*/ status) { + Contract.Requires(status != null); + Contract.Requires(sat != null); + Contract.Requires(sat.GetLength(0) == status.Length); + int M = sat.GetLength(0); + int N = sat.GetLength(1); + + for (int i = 0; i < M - 1; i++) { + if (status[i] != SimplificationStatus.Relevant) { + continue; + } + for (int j = i + 1; j < M; j++) { + if (status[j] != SimplificationStatus.Relevant) { + continue; + } + // check (sat[i,*] <= sat[j,*]) and (sat[i,*] >= sat[j,*]) + int cmp = 0; // -1: (sat[i,*] <= sat[j,*]), 0: equal, 1: (sat[i,*] >= sat[j,*]) + for (int c = 0; c < N; c++) { + if (cmp < 0) { + if (sat[i, c] && !sat[j, c]) { + // incomparable + goto NEXT_PAIR; + } + } else if (0 < cmp) { + if (!sat[i, c] && sat[j, c]) { + // incomparable + goto NEXT_PAIR; + } + } else if (sat[i, c] != sat[j, c]) { + if (!sat[i, c]) { + cmp = -1; + } else { + cmp = 1; + } + } + } + if (cmp <= 0) { + // sat[i,*] <= sat[j,*] holds, so mark i as irrelevant + status[i] = SimplificationStatus.Irrelevant; + goto NEXT_OUTER; + } else { + // sat[i,*] >= sat[j,*] holds, so mark j as irrelevant + status[j] = SimplificationStatus.Irrelevant; + } + NEXT_PAIR: { + } + } + NEXT_OUTER: { + } + } + } + + static void RemoveIrrelevantFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, SimplificationStatus[]/*!*/ status, + /*maybe null*/ ArrayList /*FrameElement*/ lines) { + Contract.Requires(ff != null); + Contract.Requires(status != null); + Contract.Requires(ff.Count == status.Length); + for (int j = ff.Count - 1; 0 <= j; j--) { + switch (status[j]) { + case SimplificationStatus.Relevant: + break; + case SimplificationStatus.Irrelevant: +#if DEBUG_PRINT + Console.WriteLine("Removing irrelevant {0}: {1}", lines == null ? "vertex" : "ray", ff[j]); +#endif + ff.RemoveAt(j); + break; + case SimplificationStatus.More: + System.Diagnostics.Debug.Assert(lines != null); + FrameElement f = (FrameElement)ff[j]; +#if DEBUG_PRINT + Console.WriteLine("Changing ray into line: {0}", f); +#endif + ff.RemoveAt(j); + Contract.Assert(lines != null); + lines.Add(f); + break; + } + } + } + + /// + /// Uses the frame to simplify Constraints. See section 3.3.1.2 of Cousot and Halbwachs. + /// + /// Note: This code does not necessarily eliminate all irrelevant equalities; Cousot and + /// Halbwachs only claim that the technique eliminates all irrelevant inequalities. + /// + void SimplifyConstraints() { + if (Constraints == null) { + return; + } + Contract.Assume(this.FrameVertices != null); + Contract.Assume(this.FrameRays != null); + + SimplificationStatus[] status = new SimplificationStatus[Constraints.Count]; + /*readonly*/ + int feCount = FrameVertices.Count + FrameRays.Count; + + // Create a table that keeps track of which constraints are satisfied by which vertices and rays + bool[,] sat = new bool[Constraints.Count, FrameVertices.Count + FrameRays.Count]; + for (int i = 0; i < Constraints.Count; i++) { + status[i] = SimplificationStatus.Relevant; + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); + int cnt = 0; // number of vertices and rays that saturate lc + for (int j = 0; j < FrameVertices.Count; j++) { + FrameElement vertex = (FrameElement/*!*/)cce.NonNull(FrameVertices[j]); + if (lc.IsSaturatedBy(vertex, true)) { + sat[i, j] = true; + cnt++; + } + } + if (cnt == 0) { + // no vertex saturates the constraint, so the constraint is irrelevant + status[i] = SimplificationStatus.Irrelevant; + continue; + } + for (int j = 0; j < FrameRays.Count; j++) { + FrameElement ray = (FrameElement/*!*/)cce.NonNull(FrameRays[j]); + if (lc.IsSaturatedBy(ray, false)) { + sat[i, FrameVertices.Count + j] = true; + cnt++; + } + } + if (cnt == feCount) { + status[i] = SimplificationStatus.More; + } else { + // Cousot and Halbwachs says that all equalities are found in the way we just tested. + // If I understand that right, then we should not get here if the constraint is an + // equality constraint. The following assertion tests my understanding. --KRML + System.Diagnostics.Debug.Assert(lc.Relation == LinearConstraint.ConstraintRelation.LE); + } + } + + CheckPairSimplifications(sat, status); + + // Finally, make the changes to the list of constraints + for (int i = Constraints.Count - 1; 0 <= i; i--) { + switch (status[i]) { + case SimplificationStatus.Relevant: + break; + case SimplificationStatus.Irrelevant: +#if DEBUG_PRINT + Console.WriteLine("Removing irrelevant constraint: {0}", Constraints[i]); +#endif + Constraints.RemoveAt(i); + break; + case SimplificationStatus.More: + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]); + if (lc.Relation == LinearConstraint.ConstraintRelation.LE) { +#if DEBUG_PRINT + Console.WriteLine("Converting the following constraint into an equality: {0}", lc); +#endif + LinearConstraint lcEq = lc.ChangeRelation(LinearConstraint.ConstraintRelation.EQ); + Constraints[i] = lcEq; + } + break; + } + } + + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + lc.Normalize(); + } + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Cloning routines -------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public LinearConstraintSystem/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + LinearConstraintSystem z = new LinearConstraintSystem(); + z.FrameDimensions = (IMutableSet /*IVariable!*//*!*/)cce.NonNull(this.FrameDimensions.Clone()); + if (this.Constraints != null) { + z.Constraints = DeeperListCopy_LC(this.Constraints); + z.FrameVertices = DeeperListCopy_FE(cce.NonNull(this.FrameVertices)); + z.FrameRays = DeeperListCopy_FE(cce.NonNull(this.FrameRays)); + z.FrameLines = DeeperListCopy_FE(cce.NonNull(this.FrameLines)); + } else { + System.Diagnostics.Debug.Assert(this.FrameVertices == null); + System.Diagnostics.Debug.Assert(this.FrameRays == null); + System.Diagnostics.Debug.Assert(this.FrameLines == null); + // the constructor should already have set these fields of z to null + System.Diagnostics.Debug.Assert(z.Constraints == null); + System.Diagnostics.Debug.Assert(z.FrameVertices == null); + System.Diagnostics.Debug.Assert(z.FrameRays == null); + System.Diagnostics.Debug.Assert(z.FrameLines == null); + } + return z; + } + + /// + /// Clones "list" and the elements of "list". + /// + /// + /// + ArrayList /*LinearConstraint*/ DeeperListCopy_LC(ArrayList/*!*/ /*LinearConstraint*/ list) { + Contract.Requires(list != null); + ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count); + foreach (LinearConstraint/*!*/ lc in list) { + Contract.Assert(lc != null); + z.Add(lc.Clone()); + } + System.Diagnostics.Debug.Assert(z.Count == list.Count); + return z; + } + + /// + /// Clones "list" and the elements of "list". + /// + /// + /// + ArrayList /*FrameElement*/ DeeperListCopy_FE(ArrayList/*!*/ /*FrameElement*/ list) { + Contract.Requires(list != null); + ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count); + foreach (FrameElement/*!*/ fe in list) { + Contract.Assert(fe != null); + z.Add(fe.Clone()); + } + System.Diagnostics.Debug.Assert(z.Count == list.Count); + return z; + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Debugging and unit test routines ---------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public void Dump() { + Console.WriteLine(" Constraints:"); + if (Constraints == null) { + Console.WriteLine(" "); + } else { + foreach (LinearConstraint cc in Constraints) { + Console.WriteLine(" {0}", cc); + } + } + + Console.WriteLine(" FrameDimensions: {0}", FrameDimensions); + + Console.WriteLine(" FrameVerticies:"); + if (FrameVertices == null) { + Console.WriteLine(" "); + } else { + foreach (FrameElement fe in FrameVertices) { + Console.WriteLine(" {0}", fe); + } + } + + Console.WriteLine(" FrameRays:"); + if (FrameRays == null) { + Console.WriteLine(" "); + } else { + foreach (FrameElement fe in FrameRays) { + Console.WriteLine(" {0}", fe); + } + } + + Console.WriteLine(" FrameLines:"); + if (FrameLines == null) { + Console.WriteLine(" "); + } else { + foreach (FrameElement fe in FrameLines) { + Console.WriteLine(" {0}", fe); + } + } + } + + class TestVariable : IVariable { + readonly string/*!*/ name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result() != null); + + return name; + } + } + + public TestVariable(string/*!*/ name) { + Contract.Requires(name != null); + this.name = name; + } + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitVariable(this); + } + } + + public static void RunValidationA() { + IVariable/*!*/ dim1 = new TestVariable("X"); + IVariable/*!*/ dim2 = new TestVariable("Y"); + IVariable/*!*/ dim3 = new TestVariable("Z"); + Contract.Assert(dim1 != null); + Contract.Assert(dim2 != null); + Contract.Assert(dim3 != null); + + FrameElement s1 = new FrameElement(); + s1.AddCoordinate(dim1, Rational.ONE); + s1.AddCoordinate(dim2, Rational.MINUS_ONE); + s1.AddCoordinate(dim3, Rational.ZERO); + FrameElement s2 = new FrameElement(); + s2.AddCoordinate(dim1, Rational.MINUS_ONE); + s2.AddCoordinate(dim2, Rational.ONE); + s2.AddCoordinate(dim3, Rational.ZERO); + FrameElement r1 = new FrameElement(); + r1.AddCoordinate(dim1, Rational.ZERO); + r1.AddCoordinate(dim2, Rational.ZERO); + r1.AddCoordinate(dim3, Rational.ONE); + FrameElement d1 = new FrameElement(); + d1.AddCoordinate(dim1, Rational.ONE); + d1.AddCoordinate(dim2, Rational.ONE); + d1.AddCoordinate(dim3, Rational.ZERO); + + // create lcs from frame -- cf. Cousot/Halbwachs 1978, section 3.3.1.1 + LinearConstraintSystem lcs = new LinearConstraintSystem(s1); + lcs.Dump(); + + lcs.AddVertex(s2); + lcs.Dump(); + + lcs.AddRay(r1); + lcs.Dump(); + + lcs.AddLine(d1); + lcs.Dump(); + + lcs.SimplifyConstraints(); + lcs.Dump(); + +#if LATER + lcs.GenerateFrameFromConstraints(); // should give us back the original frame... +#endif + Console.WriteLine("IsSubset? {0}", lcs.IsSubset(lcs.Clone())); + lcs.Dump(); + } + + /// + /// Tests the example in section 3.4.3 of Cousot and Halbwachs. + /// + public static void RunValidationB() { + IVariable/*!*/ X = new TestVariable("X"); + IVariable/*!*/ Y = new TestVariable("Y"); + IVariable/*!*/ Z = new TestVariable("Z"); + Contract.Assert(X != null); + Contract.Assert(Y != null); + Contract.Assert(Z != null); + ArrayList /*LinearConstraint*/ cs = new ArrayList /*LinearConstraint*/ (); + + LinearConstraint c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(X, Rational.MINUS_ONE); + c.SetCoefficient(Y, Rational.ONE); + c.SetCoefficient(Z, Rational.MINUS_ONE); + c.rhs = Rational.ZERO; + cs.Add(c); + + c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(X, Rational.MINUS_ONE); + c.rhs = Rational.MINUS_ONE; + cs.Add(c); + + c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(X, Rational.MINUS_ONE); + c.SetCoefficient(Y, Rational.MINUS_ONE); + c.SetCoefficient(Z, Rational.ONE); + c.rhs = Rational.ZERO; + cs.Add(c); + + c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE); + c.SetCoefficient(Y, Rational.MINUS_ONE); + c.SetCoefficient(Z, Rational.ONE); + c.rhs = Rational.FromInt(3); + cs.Add(c); + + LinearConstraintSystem lcs = new LinearConstraintSystem(cs); + Console.WriteLine("==================== The final linear constraint system ===================="); + lcs.Dump(); + } + + public static void RunValidationC() { + // Run the example in section 3.4.3 of Cousot and Halbwachs backwards, that is, from + // from to constraints. + IVariable/*!*/ dim1 = new TestVariable("X"); + IVariable/*!*/ dim2 = new TestVariable("Y"); + IVariable/*!*/ dim3 = new TestVariable("Z"); + Contract.Assert(dim1 != null); + Contract.Assert(dim2 != null); + Contract.Assert(dim3 != null); + + FrameElement s0 = new FrameElement(); + s0.AddCoordinate(dim1, Rational.ONE); + s0.AddCoordinate(dim2, Rational.FromInts(1, 2)); + s0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); + + FrameElement s1 = new FrameElement(); + s1.AddCoordinate(dim1, Rational.ONE); + s1.AddCoordinate(dim2, Rational.FromInts(-1, 2)); + s1.AddCoordinate(dim3, Rational.FromInts(1, 2)); + + FrameElement s2 = new FrameElement(); + s2.AddCoordinate(dim1, Rational.FromInt(3)); + s2.AddCoordinate(dim2, Rational.FromInts(-3, 2)); + s2.AddCoordinate(dim3, Rational.FromInts(3, 2)); + + FrameElement r0 = new FrameElement(); + r0.AddCoordinate(dim1, Rational.ONE); + r0.AddCoordinate(dim2, Rational.FromInts(1, 2)); + r0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); + + FrameElement r1 = new FrameElement(); + r1.AddCoordinate(dim1, Rational.ONE); + r1.AddCoordinate(dim2, Rational.ZERO); + r1.AddCoordinate(dim3, Rational.ZERO); + + FrameElement d0 = new FrameElement(); + d0.AddCoordinate(dim1, Rational.ZERO); + d0.AddCoordinate(dim2, Rational.ONE); + d0.AddCoordinate(dim3, Rational.ONE); + + LinearConstraintSystem lcs = new LinearConstraintSystem(s0); + lcs.Dump(); + + lcs.AddVertex(s1); + lcs.Dump(); + + lcs.AddVertex(s2); + lcs.Dump(); + + lcs.AddRay(r0); + lcs.Dump(); + + lcs.AddRay(r1); + lcs.Dump(); + + lcs.AddLine(d0); + lcs.Dump(); + + lcs.SimplifyConstraints(); + lcs.Dump(); + +#if LATER + lcs.GenerateFrameFromConstraints(); // should give us back the original frame... +#endif + } + } } \ No newline at end of file diff --git a/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs index 06c0f483..6c914a54 100644 --- a/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs +++ b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs @@ -1,762 +1,762 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - - using ISet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - /// - /// Represents an invariant over linear variable constraints, represented by a polyhedron. - /// - public class PolyhedraLattice : Lattice { - private static readonly Logger/*!*/ log = new Logger("Polyhedra"); - - private class PolyhedraLatticeElement : Element { - - public LinearConstraintSystem/*!*/ lcs; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(lcs != null); - } - - - /// - /// Creates a top or bottom elements, according to parameter "top". - /// - public PolyhedraLatticeElement(bool top) { - if (top) { - lcs = new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); - } else { - lcs = new LinearConstraintSystem(); - } - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return lcs.ToString(); - } - - public override void Dump(string/*!*/ msg) { - //Contract.Requires(msg != null); - System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg); - lcs.Dump(); - } - - [Pure] - public override ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return lcs.FreeVariables(); - } - - public PolyhedraLatticeElement(LinearConstraintSystem/*!*/ lcs) { - Contract.Requires(lcs != null); - this.lcs = lcs; - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new PolyhedraLatticeElement(cce.NonNull(lcs.Clone())); - } - - } // class - - readonly ILinearExprFactory/*!*/ factory; - readonly IPropExprFactory/*!*/ propFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(log != null); - Contract.Invariant(factory != null); - Contract.Invariant(propFactory != null); - } - - - public PolyhedraLattice(ILinearExprFactory/*!*/ linearFactory, IPropExprFactory/*!*/ propFactory) - : base(linearFactory) { - Contract.Requires(propFactory != null); - Contract.Requires(linearFactory != null); - log.Enabled = Lattice.LogSwitch; - this.factory = linearFactory; - this.propFactory = propFactory; - // base(linearFactory); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new PolyhedraLatticeElement(true); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - - return new PolyhedraLatticeElement(false); - } - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; - return e.lcs.IsBottom(); - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; - return e.lcs.IsTop(); - } - - - /// - /// Returns true iff a is a subset of this. - /// - /// - /// - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first != null); - //Contract.Requires(second != null); - PolyhedraLatticeElement a = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement b = (PolyhedraLatticeElement)second; - return b.lcs.IsSubset(a.lcs); - } - - - public override string/*!*/ ToString(Element/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - return ((PolyhedraLatticeElement)e).lcs.ToString(); - } - - public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; - return e.lcs.ConvertToExpression(factory); - } - - - - public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg("Joining ..."); - log.DbgMsgIndent(); - PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; - PolyhedraLatticeElement result = new PolyhedraLatticeElement(aa.lcs.Join(bb.lcs)); - log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); - log.DbgMsgUnindent(); - return result; - } - - - public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; - return new PolyhedraLatticeElement(aa.lcs.Meet(bb.lcs)); - } - - - public override Lattice.Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg("Widening ..."); - log.DbgMsgIndent(); - PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; - PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; - - LinearConstraintSystem lcs = aa.lcs.Widen(bb.lcs); - PolyhedraLatticeElement result = new PolyhedraLatticeElement(lcs); - log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); - log.DbgMsgUnindent(); - return result; - } - - - public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg(string.Format("Eliminating {0} ...", variable)); - - PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; - if (ple.lcs.IsBottom()) { - return ple; - } - return new PolyhedraLatticeElement(ple.lcs.Project(variable)); - } - - - public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg(string.Format("Renaming {0} to {1} in {2} ...", oldName, newName, this.ToString(e))); - - PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; - if (ple.lcs.IsBottom()) { - return ple; - } - return new PolyhedraLatticeElement(ple.lcs.Rename(oldName, newName)); - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - return f is IntSymbol || - f.Equals(Int.Add) || - f.Equals(Int.Sub) || - f.Equals(Int.Negate) || - f.Equals(Int.Mul) || - f.Equals(Int.Eq) || - f.Equals(Int.Neq) || - f.Equals(Prop.Not) || - f.Equals(Int.AtMost) || - f.Equals(Int.Less) || - f.Equals(Int.Greater) || - f.Equals(Int.AtLeast); - } - - public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(e != null); - PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)cce.NonNull(e); - Contract.Assume(ple.lcs.Constraints != null); - ArrayList /*LinearConstraint!*//*!*/ clist = (ArrayList /*LinearConstraint!*/)cce.NonNull(ple.lcs.Constraints.Clone()); - LinearConstraint/*!*/ lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - Contract.Assert(lc != null); - lc.SetCoefficient(var1, Rational.ONE); - lc.SetCoefficient(var2, Rational.MINUS_ONE); - clist.Add(lc); - LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); - if (newLcs.IsBottom()) { - return Answer.Yes; - } else { - return Answer.Maybe; - } - } - - public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(e != null); - PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)Constrain(e, pred); - Contract.Assert(ple != null); - if (ple.lcs.IsBottom()) { - return Answer.No; - } - - // Note, "pred" may contain expressions that are not understood by the propFactory (in - // particular, this may happen because--currently, and perhaps is a design we'll want - // to change in the future--propFactory deals with BoogiePL expressions whereas "pred" - // may also refer to Equivalences.UninterpFun expressions). Thus, we cannot just - // call propFactory.Not(pred) to get the negation of "pred". - pred = new PolyhedraLatticeNegation(pred); - ple = (PolyhedraLatticeElement)Constrain(e, pred); - if (ple.lcs.IsBottom()) { - return Answer.Yes; - } else { - return Answer.Maybe; - } - } - - class PolyhedraLatticeNegation : IFunApp { - IExpr/*!*/ arg; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(arg != null); - } - - - public PolyhedraLatticeNegation(IExpr/*!*/ arg) { - Contract.Requires(arg != null); - this.arg = arg; - // base(); - } - - [Pure] - public object DoVisit(ExprVisitor/*!*/ visitor) { - //Contract.Requires(visitor != null); - return visitor.VisitFunApp(this); - } - - public IFunctionSymbol/*!*/ FunctionSymbol { - get { - Contract.Ensures(Contract.Result() != null); - return Prop.Not; - } - } - - public IList/**//*!*/ Arguments { - get { - Contract.Ensures(Contract.Result() != null); - - IExpr[] args = new IExpr[] { arg }; - return ArrayList.ReadOnly(args); - } - } - - public IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - Contract.Assert(args.Count == 1); - return new PolyhedraLatticeNegation((IExpr/*!*/)cce.NonNull(args[0])); - } - } - - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(e != null); - // BUGBUG: TODO: this method can be implemented in a more precise way - return null; - } - - - public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - log.DbgMsg(string.Format("Constraining with {0} into {1} ...", expr, this.ToString(e))); - - PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; - if (ple.lcs.IsBottom()) { - return ple; - } - LinearCondition le = LinearExpressionBuilder.AsCondition(expr); - if (le != null) { - // update the polyhedron according to the linear expression - Contract.Assume(ple.lcs.Constraints != null); - ArrayList /*LinearConstraint*/ clist = (ArrayList/*!*/ /*LinearConstraint*/)cce.NonNull(ple.lcs.Constraints.Clone()); - le.AddToConstraintSystem(clist); - LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); - - return new PolyhedraLatticeElement(newLcs); - } - return ple; - } - - } // class - - - /// - /// A LinearCondition follows this grammar: - /// LinearCondition ::= unsatisfiable - /// | LinearConstraint - /// | ! LinearConstraint - /// Note that negations are distributed to the leaves. - /// - /// - [ContractClass(typeof(LinearConditionContracts))] - abstract class LinearCondition { - /// - /// Adds constraints to the list "clist". If "this" - /// entails some disjunctive constraints, they may not be added. - /// - /// - public abstract void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist); - } - [ContractClassFor(typeof(LinearCondition))] - abstract class LinearConditionContracts : LinearCondition { - public override void AddToConstraintSystem(ArrayList clist) { - Contract.Requires(clist != null); - throw new NotImplementedException(); - } - } - - class LCBottom : LinearCondition { - public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { - //Contract.Requires(clist != null); - // make an unsatisfiable constraint - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - lc.rhs = Rational.FromInt(1); - clist.Add(lc); - } - } - - class LinearConditionLiteral : LinearCondition { - public readonly bool positive; - public readonly LinearConstraint/*!*/ constraint; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(constraint != null); - } - - /// - /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ - /// - /// - /// - public LinearConditionLiteral(bool positive, LinearConstraint/*!*/ constraint) { - Contract.Requires(constraint != null); - Contract.Requires(positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ); - this.positive = positive; - this.constraint = constraint; - } - public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { - //Contract.Requires(clist != null); - if (positive) { - clist.Add(constraint); - } else { - Contract.Assert(constraint.Relation == LinearConstraint.ConstraintRelation.EQ); - // the constraint is disjunctive, so just ignore it - } - } - } - - class LinearExpressionBuilder { - /// - /// Builds a linear condition from "e", if possible; returns null if not possible. - /// - /// - /// - public static /*maybe null*/ LinearCondition AsCondition(IExpr e) /* throws ArithmeticException */ - { - return GetCond(e, true); - } - - static /*maybe null*/ LinearCondition GetCond(IExpr e, bool positive) /* throws ArithmeticException */ - { - IFunApp funapp = e as IFunApp; - if (funapp == null) { - return null; - } - IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; - Contract.Assert(s != null); - if ((positive && s.Equals(Prop.False)) || - (!positive && s.Equals(Prop.True))) { - return new LCBottom(); - } else if (s.Equals(Prop.Not)) { - Contract.Assert(funapp.Arguments.Count == 1); - return GetCond((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]), !positive); - } else if (funapp.Arguments.Count == 2) { - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); - LinearExpr le0 = AsExpr(arg0); - if (le0 == null) { - return null; - } - LinearExpr le1 = AsExpr(arg1); - if (le1 == null) { - return null; - } - - LinearConstraint constraint = null; - bool sense = true; - if ((positive && s.Equals(Int.Less)) || (!positive && s.Equals(Int.AtLeast))) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); - } else if ((positive && s.Equals(Int.AtMost)) || (!positive && s.Equals(Int.Greater))) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); - } else if ((positive && s.Equals(Int.AtLeast)) || (!positive && s.Equals(Int.Less))) { - constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); - } else if ((positive && s.Equals(Int.Greater)) || (!positive && s.Equals(Int.AtMost))) { - constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); - } else if (s.Equals(Int.Eq)) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); - sense = positive; - } else if (s.Equals(Int.Neq)) { - constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); - sense = !positive; - } - if (constraint != null) { - if (constraint.coefficients.Count != 0) { - return new LinearConditionLiteral(sense, constraint); - } else if (constraint.IsConstantSatisfiable()) { - return null; - } else { - return new LCBottom(); - } - } - } - return null; - } - - public static LinearConstraint MakeConstraint(LinearExpr/*!*/ le0, LinearExpr/*!*/ le1, - LinearConstraint.ConstraintRelation rel, BigNum constantOffset) /* throws ArithmeticException */ - { - Contract.Requires(le0 != null); - Contract.Requires(le1 != null); - le1.Negate(); - le0.Add(le1); - le0.AddConstant(constantOffset); - return le0.ToConstraint(rel); - } - - /// - /// Builds a linear expression from "e", if possible; returns null if not possible. - /// - /// - /// - public static /*maybe null*/ LinearExpr AsExpr(IExpr/*!*/ e) /* throws ArithmeticException */ - { - Contract.Requires(e != null); - if (e is IVariable) { - // Note, without a type for the variable, we don't know if the identifier is intended to hold an integer value. - // However, it seems that no harm can be caused by here treating the identifier as if it held an - // integer value, because other parts of this method will reject the expression as a linear expression - // if non-numeric operations other than equality are applied to the identifier. - return new LinearExpr((IVariable)e); - } else if (e is IFunApp) { - IFunApp/*!*/ funapp = (IFunApp)e; - Contract.Assert(funapp != null); - IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; - Contract.Assert(s != null); - - if (s is IntSymbol) { - return new LinearExpr(((IntSymbol)s).Value); - } else if (s.Equals(Int.Negate)) { - Contract.Assert(funapp.Arguments.Count == 1); - LinearExpr le = AsExpr((IExpr/*!*/)cce.NonNull(funapp.Arguments[0])); - if (le != null) { - le.Negate(); - return le; - } - } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) { - Contract.Assert(funapp.Arguments.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); - LinearExpr le0 = AsExpr(arg0); - if (le0 == null) { - return null; - } - LinearExpr le1 = AsExpr(arg1); - if (le1 == null) { - return null; - } - - if (s.Equals(Int.Add)) { - le0.Add(le1); - return le0; - } else if (s.Equals(Int.Sub)) { - le1.Negate(); - le0.Add(le1); - return le0; - } else if (s.Equals(Int.Mul)) { - BigNum x; - if (le0.AsConstant(out x)) { - le1.Multiply(x); - return le1; - } else if (le1.AsConstant(out x)) { - le0.Multiply(x); - return le0; - } - } - } - } - return null; - } - } - - class LinearExpr { - BigNum constant; - Term terms; - - class Term { - public BigNum coeff; // non-0, if the node is used - public IVariable/*!*/ var; - public Term next; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(var != null); - } - - public Term(BigNum coeff, IVariable/*!*/ var) { - Contract.Requires(var != null); - this.coeff = coeff; - this.var = var; - // base(); - } - } - - public LinearExpr(BigNum x) { - constant = x; - } - - public LinearExpr(IVariable/*!*/ var) { - Contract.Requires(var != null); - constant = BigNum.ZERO; - terms = new Term(BigNum.ONE, var); - } - - public ISet /*IVariable!*/ GetDefinedDimensions() { - HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); - for (Term current = terms; current != null; current = current.next) { - dims.Add(current.var); - } - return dims; - } - - public BigNum TermCoefficient(/*MayBeNull*/ IVariable/*!*/ var) { - Contract.Requires(var != null); - BigNum z = BigNum.ZERO; - if (var == null) { - z = this.constant; - } else if (terms != null) { - Term current = terms; - while (current != null) { - if (current.var == var) { - break; - } - current = current.next; - } - if (current != null) { - z = current.coeff; - } - } - return z; - } - - public bool AsConstant(out BigNum x) { - if (terms == null) { - x = constant; - return true; - } else { - x = BigNum.FromInt(-70022); // to please complier - return false; - } - } - - public void Negate() /* throws ArithmeticException */ - { - checked { - constant = -constant; - } - - for (Term t = terms; t != null; t = t.next) { - checked { - t.coeff = -t.coeff; - } - } - } - - /// - /// Adds "x" to "this". - /// - /// - public void AddConstant(BigNum x) /* throws ArithmeticException */ - { - checked { - constant += x; - } - } - - /// - /// Adds "le" to "this". Afterwards, "le" should not be used, because it will have been destroyed. - /// - /// - public void Add(LinearExpr/*!*/ le) /* throws ArithmeticException */ - { - Contract.Requires(le != null); - Contract.Requires(le != this); - checked { - constant += le.constant; - } - le.constant = BigNum.FromInt(-70029); // "le" should no longer be used; assign it a strange value so that misuse is perhaps more easily detected - - // optimization: - if (le.terms == null) { - return; - } else if (terms == null) { - terms = le.terms; - le.terms = null; - return; - } - - // merge the two term lists - // Use a nested loop, which is quadratic in time complexity, but we hope the lists will be small - Term newTerms = null; - while (le.terms != null) { - // take off next term from "le" - Term t = le.terms; - le.terms = t.next; - t.next = null; - - for (Term u = terms; u != null; u = u.next) { - if (u.var == t.var) { - checked { - u.coeff += t.coeff; - } - goto NextOuter; - } - } - t.next = newTerms; - newTerms = t; - - NextOuter: - ; - } - - // finally, include all non-0 terms - while (terms != null) { - // take off next term from "this" - Term t = terms; - terms = t.next; - - if (!t.coeff.IsZero) { - t.next = newTerms; - newTerms = t; - } - } - terms = newTerms; - } - - public void Multiply(BigNum x) /* throws ArithmeticException */ - { - if (x.IsZero) { - constant = BigNum.ZERO; - terms = null; - } else { - for (Term t = terms; t != null; t = t.next) { - checked { - t.coeff *= x; - } - } - checked { - constant *= x; - } - } - } - - public bool IsInvertible(IVariable/*!*/ var) { - Contract.Requires(var != null); - for (Term t = terms; t != null; t = t.next) { - if (t.var == var) { - System.Diagnostics.Debug.Assert(!t.coeff.IsZero); - return true; - } - } - return false; - } - - public LinearConstraint ToConstraint(LinearConstraint.ConstraintRelation rel) /* throws ArithmeticException */ - { - LinearConstraint constraint = new LinearConstraint(rel); - for (Term t = terms; t != null; t = t.next) { - constraint.SetCoefficient(t.var, t.coeff.ToRational); - } - BigNum rhs = -constant; - constraint.rhs = rhs.ToRational; - return constraint; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using ISet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + /// + /// Represents an invariant over linear variable constraints, represented by a polyhedron. + /// + public class PolyhedraLattice : Lattice { + private static readonly Logger/*!*/ log = new Logger("Polyhedra"); + + private class PolyhedraLatticeElement : Element { + + public LinearConstraintSystem/*!*/ lcs; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lcs != null); + } + + + /// + /// Creates a top or bottom elements, according to parameter "top". + /// + public PolyhedraLatticeElement(bool top) { + if (top) { + lcs = new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); + } else { + lcs = new LinearConstraintSystem(); + } + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return lcs.ToString(); + } + + public override void Dump(string/*!*/ msg) { + //Contract.Requires(msg != null); + System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg); + lcs.Dump(); + } + + [Pure] + public override ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return lcs.FreeVariables(); + } + + public PolyhedraLatticeElement(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + this.lcs = lcs; + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new PolyhedraLatticeElement(cce.NonNull(lcs.Clone())); + } + + } // class + + readonly ILinearExprFactory/*!*/ factory; + readonly IPropExprFactory/*!*/ propFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(log != null); + Contract.Invariant(factory != null); + Contract.Invariant(propFactory != null); + } + + + public PolyhedraLattice(ILinearExprFactory/*!*/ linearFactory, IPropExprFactory/*!*/ propFactory) + : base(linearFactory) { + Contract.Requires(propFactory != null); + Contract.Requires(linearFactory != null); + log.Enabled = Lattice.LogSwitch; + this.factory = linearFactory; + this.propFactory = propFactory; + // base(linearFactory); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new PolyhedraLatticeElement(true); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + + return new PolyhedraLatticeElement(false); + } + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.IsBottom(); + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.IsTop(); + } + + + /// + /// Returns true iff a is a subset of this. + /// + /// + /// + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + PolyhedraLatticeElement a = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement b = (PolyhedraLatticeElement)second; + return b.lcs.IsSubset(a.lcs); + } + + + public override string/*!*/ ToString(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + return ((PolyhedraLatticeElement)e).lcs.ToString(); + } + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.ConvertToExpression(factory); + } + + + + public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg("Joining ..."); + log.DbgMsgIndent(); + PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; + PolyhedraLatticeElement result = new PolyhedraLatticeElement(aa.lcs.Join(bb.lcs)); + log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); + log.DbgMsgUnindent(); + return result; + } + + + public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; + return new PolyhedraLatticeElement(aa.lcs.Meet(bb.lcs)); + } + + + public override Lattice.Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg("Widening ..."); + log.DbgMsgIndent(); + PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second; + + LinearConstraintSystem lcs = aa.lcs.Widen(bb.lcs); + PolyhedraLatticeElement result = new PolyhedraLatticeElement(lcs); + log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result))); + log.DbgMsgUnindent(); + return result; + } + + + public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg(string.Format("Eliminating {0} ...", variable)); + + PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; + if (ple.lcs.IsBottom()) { + return ple; + } + return new PolyhedraLatticeElement(ple.lcs.Project(variable)); + } + + + public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg(string.Format("Renaming {0} to {1} in {2} ...", oldName, newName, this.ToString(e))); + + PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; + if (ple.lcs.IsBottom()) { + return ple; + } + return new PolyhedraLatticeElement(ple.lcs.Rename(oldName, newName)); + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f is IntSymbol || + f.Equals(Int.Add) || + f.Equals(Int.Sub) || + f.Equals(Int.Negate) || + f.Equals(Int.Mul) || + f.Equals(Int.Eq) || + f.Equals(Int.Neq) || + f.Equals(Prop.Not) || + f.Equals(Int.AtMost) || + f.Equals(Int.Less) || + f.Equals(Int.Greater) || + f.Equals(Int.AtLeast); + } + + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)cce.NonNull(e); + Contract.Assume(ple.lcs.Constraints != null); + ArrayList /*LinearConstraint!*//*!*/ clist = (ArrayList /*LinearConstraint!*/)cce.NonNull(ple.lcs.Constraints.Clone()); + LinearConstraint/*!*/ lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + Contract.Assert(lc != null); + lc.SetCoefficient(var1, Rational.ONE); + lc.SetCoefficient(var2, Rational.MINUS_ONE); + clist.Add(lc); + LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); + if (newLcs.IsBottom()) { + return Answer.Yes; + } else { + return Answer.Maybe; + } + } + + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)Constrain(e, pred); + Contract.Assert(ple != null); + if (ple.lcs.IsBottom()) { + return Answer.No; + } + + // Note, "pred" may contain expressions that are not understood by the propFactory (in + // particular, this may happen because--currently, and perhaps is a design we'll want + // to change in the future--propFactory deals with BoogiePL expressions whereas "pred" + // may also refer to Equivalences.UninterpFun expressions). Thus, we cannot just + // call propFactory.Not(pred) to get the negation of "pred". + pred = new PolyhedraLatticeNegation(pred); + ple = (PolyhedraLatticeElement)Constrain(e, pred); + if (ple.lcs.IsBottom()) { + return Answer.Yes; + } else { + return Answer.Maybe; + } + } + + class PolyhedraLatticeNegation : IFunApp { + IExpr/*!*/ arg; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(arg != null); + } + + + public PolyhedraLatticeNegation(IExpr/*!*/ arg) { + Contract.Requires(arg != null); + this.arg = arg; + // base(); + } + + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitFunApp(this); + } + + public IFunctionSymbol/*!*/ FunctionSymbol { + get { + Contract.Ensures(Contract.Result() != null); + return Prop.Not; + } + } + + public IList/**//*!*/ Arguments { + get { + Contract.Ensures(Contract.Result() != null); + + IExpr[] args = new IExpr[] { arg }; + return ArrayList.ReadOnly(args); + } + } + + public IFunApp/*!*/ CloneWithArguments(IList/**//*!*/ args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + Contract.Assert(args.Count == 1); + return new PolyhedraLatticeNegation((IExpr/*!*/)cce.NonNull(args[0])); + } + } + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + // BUGBUG: TODO: this method can be implemented in a more precise way + return null; + } + + + public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + log.DbgMsg(string.Format("Constraining with {0} into {1} ...", expr, this.ToString(e))); + + PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e; + if (ple.lcs.IsBottom()) { + return ple; + } + LinearCondition le = LinearExpressionBuilder.AsCondition(expr); + if (le != null) { + // update the polyhedron according to the linear expression + Contract.Assume(ple.lcs.Constraints != null); + ArrayList /*LinearConstraint*/ clist = (ArrayList/*!*/ /*LinearConstraint*/)cce.NonNull(ple.lcs.Constraints.Clone()); + le.AddToConstraintSystem(clist); + LinearConstraintSystem newLcs = new LinearConstraintSystem(clist); + + return new PolyhedraLatticeElement(newLcs); + } + return ple; + } + + } // class + + + /// + /// A LinearCondition follows this grammar: + /// LinearCondition ::= unsatisfiable + /// | LinearConstraint + /// | ! LinearConstraint + /// Note that negations are distributed to the leaves. + /// + /// + [ContractClass(typeof(LinearConditionContracts))] + abstract class LinearCondition { + /// + /// Adds constraints to the list "clist". If "this" + /// entails some disjunctive constraints, they may not be added. + /// + /// + public abstract void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist); + } + [ContractClassFor(typeof(LinearCondition))] + abstract class LinearConditionContracts : LinearCondition { + public override void AddToConstraintSystem(ArrayList clist) { + Contract.Requires(clist != null); + throw new NotImplementedException(); + } + } + + class LCBottom : LinearCondition { + public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { + //Contract.Requires(clist != null); + // make an unsatisfiable constraint + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + lc.rhs = Rational.FromInt(1); + clist.Add(lc); + } + } + + class LinearConditionLiteral : LinearCondition { + public readonly bool positive; + public readonly LinearConstraint/*!*/ constraint; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(constraint != null); + } + + /// + /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ + /// + /// + /// + public LinearConditionLiteral(bool positive, LinearConstraint/*!*/ constraint) { + Contract.Requires(constraint != null); + Contract.Requires(positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ); + this.positive = positive; + this.constraint = constraint; + } + public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { + //Contract.Requires(clist != null); + if (positive) { + clist.Add(constraint); + } else { + Contract.Assert(constraint.Relation == LinearConstraint.ConstraintRelation.EQ); + // the constraint is disjunctive, so just ignore it + } + } + } + + class LinearExpressionBuilder { + /// + /// Builds a linear condition from "e", if possible; returns null if not possible. + /// + /// + /// + public static /*maybe null*/ LinearCondition AsCondition(IExpr e) /* throws ArithmeticException */ + { + return GetCond(e, true); + } + + static /*maybe null*/ LinearCondition GetCond(IExpr e, bool positive) /* throws ArithmeticException */ + { + IFunApp funapp = e as IFunApp; + if (funapp == null) { + return null; + } + IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; + Contract.Assert(s != null); + if ((positive && s.Equals(Prop.False)) || + (!positive && s.Equals(Prop.True))) { + return new LCBottom(); + } else if (s.Equals(Prop.Not)) { + Contract.Assert(funapp.Arguments.Count == 1); + return GetCond((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]), !positive); + } else if (funapp.Arguments.Count == 2) { + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); + LinearExpr le0 = AsExpr(arg0); + if (le0 == null) { + return null; + } + LinearExpr le1 = AsExpr(arg1); + if (le1 == null) { + return null; + } + + LinearConstraint constraint = null; + bool sense = true; + if ((positive && s.Equals(Int.Less)) || (!positive && s.Equals(Int.AtLeast))) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); + } else if ((positive && s.Equals(Int.AtMost)) || (!positive && s.Equals(Int.Greater))) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); + } else if ((positive && s.Equals(Int.AtLeast)) || (!positive && s.Equals(Int.Less))) { + constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO); + } else if ((positive && s.Equals(Int.Greater)) || (!positive && s.Equals(Int.AtMost))) { + constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ONE); + } else if (s.Equals(Int.Eq)) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); + sense = positive; + } else if (s.Equals(Int.Neq)) { + constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO); + sense = !positive; + } + if (constraint != null) { + if (constraint.coefficients.Count != 0) { + return new LinearConditionLiteral(sense, constraint); + } else if (constraint.IsConstantSatisfiable()) { + return null; + } else { + return new LCBottom(); + } + } + } + return null; + } + + public static LinearConstraint MakeConstraint(LinearExpr/*!*/ le0, LinearExpr/*!*/ le1, + LinearConstraint.ConstraintRelation rel, BigNum constantOffset) /* throws ArithmeticException */ + { + Contract.Requires(le0 != null); + Contract.Requires(le1 != null); + le1.Negate(); + le0.Add(le1); + le0.AddConstant(constantOffset); + return le0.ToConstraint(rel); + } + + /// + /// Builds a linear expression from "e", if possible; returns null if not possible. + /// + /// + /// + public static /*maybe null*/ LinearExpr AsExpr(IExpr/*!*/ e) /* throws ArithmeticException */ + { + Contract.Requires(e != null); + if (e is IVariable) { + // Note, without a type for the variable, we don't know if the identifier is intended to hold an integer value. + // However, it seems that no harm can be caused by here treating the identifier as if it held an + // integer value, because other parts of this method will reject the expression as a linear expression + // if non-numeric operations other than equality are applied to the identifier. + return new LinearExpr((IVariable)e); + } else if (e is IFunApp) { + IFunApp/*!*/ funapp = (IFunApp)e; + Contract.Assert(funapp != null); + IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; + Contract.Assert(s != null); + + if (s is IntSymbol) { + return new LinearExpr(((IntSymbol)s).Value); + } else if (s.Equals(Int.Negate)) { + Contract.Assert(funapp.Arguments.Count == 1); + LinearExpr le = AsExpr((IExpr/*!*/)cce.NonNull(funapp.Arguments[0])); + if (le != null) { + le.Negate(); + return le; + } + } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) { + Contract.Assert(funapp.Arguments.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[1]); + LinearExpr le0 = AsExpr(arg0); + if (le0 == null) { + return null; + } + LinearExpr le1 = AsExpr(arg1); + if (le1 == null) { + return null; + } + + if (s.Equals(Int.Add)) { + le0.Add(le1); + return le0; + } else if (s.Equals(Int.Sub)) { + le1.Negate(); + le0.Add(le1); + return le0; + } else if (s.Equals(Int.Mul)) { + BigNum x; + if (le0.AsConstant(out x)) { + le1.Multiply(x); + return le1; + } else if (le1.AsConstant(out x)) { + le0.Multiply(x); + return le0; + } + } + } + } + return null; + } + } + + class LinearExpr { + BigNum constant; + Term terms; + + class Term { + public BigNum coeff; // non-0, if the node is used + public IVariable/*!*/ var; + public Term next; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(var != null); + } + + public Term(BigNum coeff, IVariable/*!*/ var) { + Contract.Requires(var != null); + this.coeff = coeff; + this.var = var; + // base(); + } + } + + public LinearExpr(BigNum x) { + constant = x; + } + + public LinearExpr(IVariable/*!*/ var) { + Contract.Requires(var != null); + constant = BigNum.ZERO; + terms = new Term(BigNum.ONE, var); + } + + public ISet /*IVariable!*/ GetDefinedDimensions() { + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); + for (Term current = terms; current != null; current = current.next) { + dims.Add(current.var); + } + return dims; + } + + public BigNum TermCoefficient(/*MayBeNull*/ IVariable/*!*/ var) { + Contract.Requires(var != null); + BigNum z = BigNum.ZERO; + if (var == null) { + z = this.constant; + } else if (terms != null) { + Term current = terms; + while (current != null) { + if (current.var == var) { + break; + } + current = current.next; + } + if (current != null) { + z = current.coeff; + } + } + return z; + } + + public bool AsConstant(out BigNum x) { + if (terms == null) { + x = constant; + return true; + } else { + x = BigNum.FromInt(-70022); // to please complier + return false; + } + } + + public void Negate() /* throws ArithmeticException */ + { + checked { + constant = -constant; + } + + for (Term t = terms; t != null; t = t.next) { + checked { + t.coeff = -t.coeff; + } + } + } + + /// + /// Adds "x" to "this". + /// + /// + public void AddConstant(BigNum x) /* throws ArithmeticException */ + { + checked { + constant += x; + } + } + + /// + /// Adds "le" to "this". Afterwards, "le" should not be used, because it will have been destroyed. + /// + /// + public void Add(LinearExpr/*!*/ le) /* throws ArithmeticException */ + { + Contract.Requires(le != null); + Contract.Requires(le != this); + checked { + constant += le.constant; + } + le.constant = BigNum.FromInt(-70029); // "le" should no longer be used; assign it a strange value so that misuse is perhaps more easily detected + + // optimization: + if (le.terms == null) { + return; + } else if (terms == null) { + terms = le.terms; + le.terms = null; + return; + } + + // merge the two term lists + // Use a nested loop, which is quadratic in time complexity, but we hope the lists will be small + Term newTerms = null; + while (le.terms != null) { + // take off next term from "le" + Term t = le.terms; + le.terms = t.next; + t.next = null; + + for (Term u = terms; u != null; u = u.next) { + if (u.var == t.var) { + checked { + u.coeff += t.coeff; + } + goto NextOuter; + } + } + t.next = newTerms; + newTerms = t; + + NextOuter: + ; + } + + // finally, include all non-0 terms + while (terms != null) { + // take off next term from "this" + Term t = terms; + terms = t.next; + + if (!t.coeff.IsZero) { + t.next = newTerms; + newTerms = t; + } + } + terms = newTerms; + } + + public void Multiply(BigNum x) /* throws ArithmeticException */ + { + if (x.IsZero) { + constant = BigNum.ZERO; + terms = null; + } else { + for (Term t = terms; t != null; t = t.next) { + checked { + t.coeff *= x; + } + } + checked { + constant *= x; + } + } + } + + public bool IsInvertible(IVariable/*!*/ var) { + Contract.Requires(var != null); + for (Term t = terms; t != null; t = t.next) { + if (t.var == var) { + System.Diagnostics.Debug.Assert(!t.coeff.IsZero); + return true; + } + } + return false; + } + + public LinearConstraint ToConstraint(LinearConstraint.ConstraintRelation rel) /* throws ArithmeticException */ + { + LinearConstraint constraint = new LinearConstraint(rel); + for (Term t = terms; t != null; t = t.next) { + constraint.SetCoefficient(t.var, t.coeff.ToRational); + } + BigNum rhs = -constant; + constraint.rhs = rhs.ToRational; + return constraint; + } + } +} diff --git a/Source/AIFramework/Polyhedra/SimplexTableau.cs b/Source/AIFramework/Polyhedra/SimplexTableau.cs index 4d734c27..347c7c45 100644 --- a/Source/AIFramework/Polyhedra/SimplexTableau.cs +++ b/Source/AIFramework/Polyhedra/SimplexTableau.cs @@ -1,630 +1,630 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - using IMutableSet = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - - /// - /// Used by LinearConstraintSystem.GenerateFrameFromConstraints. - /// - public class SimplexTableau { - readonly int rows; - readonly int columns; - readonly Rational[,]/*!*/ m; - - readonly int numInitialVars; - readonly int numSlackVars; - readonly int rhsColumn; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(m != null); - Contract.Invariant(inBasis != null); - Contract.Invariant(basisColumns != null); - } - - readonly ArrayList /*IVariable!*//*!*/ dims; - readonly int[]/*!*/ basisColumns; - readonly int[]/*!*/ inBasis; - bool constructionDone = false; - - void CheckInvariant() { - Contract.Assert(rows == m.GetLength(0)); - Contract.Assert(1 <= columns && columns == m.GetLength(1)); - Contract.Assert(0 <= numInitialVars); - Contract.Assert(0 <= numSlackVars && numSlackVars <= rows); - Contract.Assert(numInitialVars + numSlackVars + 1 == columns); - Contract.Assert(rhsColumn == columns - 1); - Contract.Assert(dims.Count == numInitialVars); - Contract.Assert(basisColumns.Length == rows); - Contract.Assert(inBasis.Length == numInitialVars + numSlackVars); - - bool[] b = new bool[numInitialVars + numSlackVars]; - int numColumnsInBasis = 0; - int numUninitializedRowInfo = 0; - for (int i = 0; i < rows; i++) { - int c = basisColumns[i]; - if (c == rhsColumn) { - // all coefficients in this row are 0 (but the right-hand side may be non-0) - for (int j = 0; j < rhsColumn; j++) { - Contract.Assert(m[i, j].IsZero); - } - numColumnsInBasis++; - } else if (c == -1) { - Contract.Assert(!constructionDone); - numUninitializedRowInfo++; - } else { - // basis column is a column - Contract.Assert(0 <= c && c < numInitialVars + numSlackVars); - // basis column is unique - Contract.Assert(!b[c]); - b[c] = true; - // column is marked as being in basis - Contract.Assert(inBasis[c] == i); - // basis column really is a basis column - for (int j = 0; j < rows; j++) { - if (j == i) { - Contract.Assert(m[j, c].HasValue(1));// == (Rational)new Rational(1))); - } else { - Contract.Assert(m[j, c].IsZero); - } - } - } - } - // no other columns are marked as being in basis - foreach (int i in inBasis) { - if (0 <= i) { - Contract.Assert(i < rows); - numColumnsInBasis++; - } else { - Contract.Assert(i == -1); - } - } - Contract.Assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows); - Contract.Assert(!constructionDone || numUninitializedRowInfo == 0); - } - - /// - /// Constructs a matrix that represents the constraints "constraints", adding slack - /// variables for the inequalities among "constraints". Puts the matrix in canonical - /// form. - /// - /// - [NotDelayed] - public SimplexTableau(ArrayList /*LinearConstraint*//*!*/ constraints) { - Contract.Requires(constraints != null); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: SimplexTableau constructor called with:"); - foreach (LinearConstraint lc in constraints) - { - Console.WriteLine(" {0}", lc); - } -#endif - // Note: This implementation is not particularly efficient, but it'll do for now. - - ArrayList dims = this.dims = new ArrayList /*IVariable!*/ (); - int slacks = 0; - foreach (LinearConstraint/*!*/ cc in constraints) { - Contract.Assert(cc != null); - foreach (IVariable/*!*/ dim in cc.coefficients.Keys) { - Contract.Assert(dim != null); - if (!dims.Contains(dim)) { - dims.Add(dim); - } - } - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - slacks++; - } - } - - int numInitialVars = this.numInitialVars = dims.Count; - int numSlackVars = this.numSlackVars = slacks; - int rows = this.rows = constraints.Count; - int columns = this.columns = numInitialVars + numSlackVars + 1; - this.m = new Rational[rows, columns]; - this.rhsColumn = columns - 1; - this.basisColumns = new int[rows]; - this.inBasis = new int[columns - 1]; - - //:base(); - - for (int i = 0; i < inBasis.Length; i++) { - inBasis[i] = -1; - } - - // Fill in the matrix - int r = 0; - int iSlack = 0; - foreach (LinearConstraint/*!*/ cc in constraints) { - Contract.Assert(cc != null); - for (int i = 0; i < dims.Count; i++) { - m[r, i] = cc[(IVariable)cce.NonNull(dims[i])]; - } - if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { - m[r, numInitialVars + iSlack] = Rational.ONE; - basisColumns[r] = numInitialVars + iSlack; - inBasis[numInitialVars + iSlack] = r; - iSlack++; - } else { - basisColumns[r] = -1; // special value to communicate to Pivot that basis column i hasn't been set up yet - } - m[r, rhsColumn] = cc.rhs; - r++; - } - Contract.Assert(r == constraints.Count); - Contract.Assert(iSlack == numSlackVars); -#if DEBUG_PRINT - Console.WriteLine("DEBUG: Intermediate tableau state in SimplexTableau constructor:"); - Dump(); -#endif - - // Go through the rows with uninitialized basis columns. These correspond to equality constraints. - // For each one, find an initial variable (non-slack variable) whose column we can make the basis - // column of the row. - for (int i = 0; i < rows; i++) { - if (basisColumns[i] != -1) { - continue; - } - // Find a non-0 column in row i that we can make a basis column. Since rows corresponding - // to equality constraints don't have slack variables and since the pivot operations performed - // by iterations of this loop don't introduce any non-0 coefficients in the slack-variable - // columns of these rows, we only need to look through the columns corresponding to initial - // variables. - for (int j = 0; j < numInitialVars; j++) { - if (m[i, j].IsNonZero) { -#if DEBUG_PRINT - Console.WriteLine("-- About to Pivot({0},{1})", i, j); -#endif - Contract.Assert(inBasis[j] == -1); - Pivot(i, j); -#if DEBUG_PRINT - Console.WriteLine("Tableau after Pivot:"); - Dump(); -#endif - goto SET_UP_NEXT_INBASIS_COLUMN; - } - } - // Check the assertion in the comment above, that is, that columns corresponding to slack variables - // are 0 in this row. - for (int j = numInitialVars; j < rhsColumn; j++) { - Contract.Assert(m[i, j].IsZero); - } - // There is no column in this row that we can put into basis. - basisColumns[i] = rhsColumn; - SET_UP_NEXT_INBASIS_COLUMN: { - } - } - - constructionDone = true; - CheckInvariant(); - } - - public IMutableSet/*!*/ /*IVariable!*/ GetDimensions() { - Contract.Ensures(Contract.Result() != null); - HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ (); - foreach (IVariable/*!*/ dim in dims) { - Contract.Assert(dim != null); - z.Add(dim); - } - return z; - } - - public Rational this[int r, int c] { - get { - return m[r, c]; - } - set { - m[r, c] = value; - } - } - - /// - /// Applies the Pivot Operation on row "r" and column "c". - /// - /// This method can be called when !constructionDone, that is, at a time when not all basis - /// columns have been set up (indicated by -1 in basisColumns). This method helps set up - /// those basis columns. - /// - /// The return value is an undo record that can be used with UnPivot. - /// - /// - /// - public Rational[]/*!*/ Pivot(int r, int c) { - Contract.Ensures(Contract.Result() != null); - Contract.Assert(0 <= r && r < rows); - Contract.Assert(0 <= c && c < columns - 1); - Contract.Assert(m[r, c].IsNonZero); - Contract.Assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0 - Contract.Assert(basisColumns[r] != rhsColumn); // follows from invariant and m[r,c] != 0 - - Rational[] undo = new Rational[rows + 1]; - for (int i = 0; i < rows; i++) { - undo[i] = m[i, c]; - } - - // scale the pivot row - Rational q = m[r, c]; - if (q != Rational.ONE) { - for (int j = 0; j < columns; j++) { - m[r, j] /= q; - } - } - - // subtract a multiple of the pivot row from all other rows - for (int i = 0; i < rows; i++) { - if (i != r) { - q = m[i, c]; - if (q.IsNonZero) { - for (int j = 0; j < columns; j++) { - m[i, j] -= q * m[r, j]; - } - } - } - } - - // update basis information - int prevCol = basisColumns[r]; - undo[rows] = Rational.FromInt(prevCol); - basisColumns[r] = c; - if (prevCol != -1) { - inBasis[prevCol] = -1; - } - inBasis[c] = r; - - return undo; - } - - /// - /// If the last operation applied to the tableau was: - /// undo = Pivot(i,j); - /// then UnPivot(i, j, undo) undoes the pivot operation. - /// Note: This operation is not supported for any call to Pivot before constructionDone - /// is set to true. - /// - /// - /// - /// - void UnPivot(int r, int c, Rational[]/*!*/ undo) { - Contract.Requires(undo != null); - Contract.Assert(0 <= r && r < rows); - Contract.Assert(0 <= c && c < columns - 1); - Contract.Assert(m[r, c].HasValue(1)); - Contract.Assert(undo.Length == rows + 1); - - // add a multiple of the pivot row to all other rows - for (int i = 0; i < rows; i++) { - if (i != r) { - Rational q = undo[i]; - if (q.IsNonZero) { - for (int j = 0; j < columns; j++) { - m[i, j] += q * m[r, j]; - } - } - } - } - - // scale the pivot row - Rational p = undo[r]; - for (int j = 0; j < columns; j++) { - m[r, j] *= p; - } - - // update basis information - int prevCol = undo[rows].AsInteger; - Contract.Assert(prevCol != -1); - basisColumns[r] = prevCol; - inBasis[c] = -1; - inBasis[prevCol] = r; - } - - /// - /// Returns true iff the current basis of the system of constraints modeled by the simplex tableau - /// is feasible. May have a side effect of performing a number of pivot operations on the tableau, - /// but any such pivot operation will be in the columns of slack variables (that is, this routine - /// does not change the set of initial-variable columns in basis). - /// - /// CAVEAT: I have no particular reason to believe that the algorithm used here will terminate. --KRML - /// - /// - public bool IsFeasibleBasis { - get { - // while there is a slack variable in basis whose row has a negative right-hand side - while (true) { - bool feasibleBasis = true; - for (int c = numInitialVars; c < rhsColumn; c++) { - int k = inBasis[c]; - if (0 <= k && k < rhsColumn && m[k, rhsColumn].IsNegative) { - Contract.Assert(m[k, c].HasValue(1)); // c is in basis - // Try to pivot on a different slack variable in this row - for (int i = numInitialVars; i < rhsColumn; i++) { - if (m[k, i].IsNegative) { - Contract.Assert(c != i); // c is in basis, so m[k,c]==1, which is not negative - Pivot(k, i); -#if DEBUG_PRINT - Console.WriteLine("Tableau after Pivot operation on ({0},{1}) in IsFeasibleBasis:", k, i); - Dump(); -#endif - Contract.Assert(inBasis[c] == -1); - Contract.Assert(inBasis[i] == k); - Contract.Assert(m[k, rhsColumn].IsNonNegative); - goto START_ANEW; - } - } - feasibleBasis = false; - } - } - return feasibleBasis; - START_ANEW: - ; - } - } - } - - /// - /// Whether or not all initial variables (the non-slack variables) are in basis) - /// - public bool AllInitialVarsInBasis { - get { - for (int i = 0; i < numInitialVars; i++) { - if (inBasis[i] == -1) { - return false; - } - } - return true; - } - } - - /// - /// Adds as many initial variables as possible to the basis. - /// - /// - public void AddInitialVarsToBasis() { - // while there exists an initial variable not in the basis and not satisfying - // condition 3.4.2.2 in Cousot and Halbwachs, perform a pivot operation - while (true) { - for (int i = 0; i < numInitialVars; i++) { - if (inBasis[i] == -1) { - // initial variable i is not in the basis - for (int j = 0; j < rows; j++) { - if (m[j, i].IsNonZero) { - int k = basisColumns[j]; - if (numInitialVars <= k && k < rhsColumn) { - // slack variable k is in basis for row j - Pivot(j, i); - Contract.Assert(inBasis[k] == -1); - Contract.Assert(inBasis[i] == j && basisColumns[j] == i); - goto START_ANEW; - } - } - } - } - } - // No more initial variables can be moved into basis. - return; - START_ANEW: { - } - } - } - - /// - /// Adds to "lines" the lines implied by initial-variable columns not in basis - /// (see section 3.4.2 of Cousot and Halbwachs), and adds to "constraints" the - /// constraints to exclude those lines (see step 4.2 of section 3.4.3 of - /// Cousot and Halbwachs). - /// - /// - /// - public void ProduceLines(ArrayList /*FrameElement*//*!*/ lines, ArrayList /*LinearConstraint*//*!*/ constraints) { - Contract.Requires(constraints != null); - Contract.Requires(lines != null); - // for every initial variable not in basis - for (int i0 = 0; i0 < numInitialVars; i0++) { - if (inBasis[i0] == -1) { - FrameElement fe = new FrameElement(); - LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); - for (int i = 0; i < numInitialVars; i++) { - if (i == i0) { - fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), Rational.ONE); - lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE); - } else if (inBasis[i] != -1) { - // i is a basis column - Contract.Assert(m[inBasis[i], i].HasValue(1)); - Rational val = -m[inBasis[i], i0]; - fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); - lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), val); - } - } - lines.Add(fe); - constraints.Add(lc); - } - } - } - - /// - /// From a feasible point where all initial variables are in the basis, traverses - /// all feasible bases containing all initial variables. For each such basis, adds - /// the vertices to "vertices" and adds to "rays" the extreme rays. See step 4.2 - /// in section 3.4.3 of Cousot and Halbwachs. - /// A more efficient algorithm is found in the paper "An algorithm for - /// determining all extreme points of a convex polytope" by N. E. Dyer and L. G. Proll, - /// Mathematical Programming, 12, 1977. - /// Assumes that the tableau is in a state where all initial variables are in the basis. - /// This method has no net effect on the tableau. - /// Note: Duplicate vertices and rays may be added. - /// - /// - /// - public void TraverseVertices(ArrayList/*!*/ /*FrameElement*/ vertices, ArrayList/*!*/ /*FrameElement*/ rays) { - Contract.Requires(vertices != null); - Contract.Requires(rays != null); - ArrayList /*bool[]*/ basesSeenSoFar = new ArrayList /*bool[]*/ (); - TraverseBases(basesSeenSoFar, vertices, rays); - } - - /// - /// Worker method of TraverseVertices. - /// This method has no net effect on the tableau. - /// - /// - /// - /// - void TraverseBases(ArrayList /*bool[]*//*!*/ basesSeenSoFar, ArrayList /*FrameElement*//*!*/ vertices, ArrayList /*FrameElement*//*!*/ rays) { - Contract.Requires(rays != null); - Contract.Requires(vertices != null); - Contract.Requires(basesSeenSoFar != null); - CheckInvariant(); - - bool[] thisBasis = new bool[numSlackVars]; - for (int i = numInitialVars; i < rhsColumn; i++) { - if (inBasis[i] != -1) { - thisBasis[i - numInitialVars] = true; - } - } - foreach (bool[]/*!*/ basis in basesSeenSoFar) { - Contract.Assert(basis != null); - Contract.Assert(basis.Length == numSlackVars); - for (int i = 0; i < numSlackVars; i++) { - if (basis[i] != thisBasis[i]) { - goto COMPARE_WITH_NEXT_BASIS; - } - } - // thisBasis and basis are the same--that is, basisColumns has been visited before--so - // we don't traverse anything from here - return; - COMPARE_WITH_NEXT_BASIS: { - } - } - // basisColumns has not been seen before; record thisBasis and continue with the traversal here - basesSeenSoFar.Add(thisBasis); - -#if DEBUG_PRINT - Console.Write("TraverseBases, new basis: "); - foreach (bool t in thisBasis) { - Console.Write("{0}", t ? "*" : "."); - } - Console.WriteLine(); - Dump(); -#endif - // Add vertex - FrameElement v = new FrameElement(); - for (int i = 0; i < rows; i++) { - int j = basisColumns[i]; - if (j < numInitialVars) { - v.AddCoordinate((IVariable)cce.NonNull(dims[j]), m[i, rhsColumn]); - } - } -#if DEBUG_PRINT - Console.WriteLine(" Adding vertex: {0}", v); -#endif - vertices.Add(v); - - // Add rays. Traverse all columns corresponding to slack variables that - // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs). - for (int i0 = numInitialVars; i0 < rhsColumn; i0++) { - if (inBasis[i0] != -1) { - // skip those slack-variable columns that are in basis - continue; - } - // check if slack-variable, non-basis column i corresponds to an extreme ray - for (int row = 0; row < rows; row++) { - if (m[row, i0].IsPositive) { - for (int k = numInitialVars; k < rhsColumn; k++) { - if (inBasis[k] != -1 && m[row, k].IsNonZero) { - // does not correspond to an extreme ray - goto CHECK_NEXT_SLACK_VAR; - } - } - } - } - // corresponds to an extreme ray - FrameElement ray = new FrameElement(); - for (int i = 0; i < numInitialVars; i++) { - int j0 = inBasis[i]; - Rational val = -m[j0, i0]; - ray.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); - } -#if DEBUG_PRINT - Console.WriteLine(" Adding ray: {0}", ray); -#endif - rays.Add(ray); - CHECK_NEXT_SLACK_VAR: { - } - } - - // Continue traversal - for (int i = numInitialVars; i < rhsColumn; i++) { - int j = inBasis[i]; - if (j != -1) { - // try moving i out of basis and some other slack-variable column into basis - for (int k = numInitialVars; k < rhsColumn; k++) { - if (inBasis[k] == -1 && m[j, k].IsPositive) { - Rational[] undo = Pivot(j, k); - // check if the new basis is feasible - for (int p = 0; p < rows; p++) { - int c = basisColumns[p]; - if (numInitialVars <= c && c < rhsColumn && m[p, rhsColumn].IsNegative) { - // not feasible - goto AFTER_TRAVERSE; - } - } - TraverseBases(basesSeenSoFar, vertices, rays); - AFTER_TRAVERSE: - UnPivot(j, k, undo); - } - } - } - } - } - - public void Dump() { - // names - Console.Write(" "); - for (int i = 0; i < numInitialVars; i++) { - Console.Write(" {0,4} ", dims[i]); - } - Console.WriteLine(); - // numbers - Console.Write(" "); - for (int i = 0; i < columns; i++) { - if (i == numInitialVars || i == rhsColumn) { - Console.Write("|"); - } - Console.Write(" {0,4}", i); - if (i < rhsColumn && inBasis[i] != -1) { - Console.Write("* "); - Contract.Assert(basisColumns[inBasis[i]] == i); - } else { - Console.Write(" "); - } - } - Console.WriteLine(); - // line - Console.Write(" "); - for (int i = 0; i < columns; i++) { - if (i == numInitialVars || i == rhsColumn) { - Console.Write("+"); - } - Console.Write("---------"); - } - Console.WriteLine(); - - for (int j = 0; j < rows; j++) { - Console.Write("{0,4}: ", basisColumns[j]); - for (int i = 0; i < columns; i++) { - if (i == numInitialVars || i == rhsColumn) { - Console.Write("|"); - } - Console.Write(" {0,4:n1} ", m[j, i]); - } - Console.WriteLine(); - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + using IMutableSet = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + + /// + /// Used by LinearConstraintSystem.GenerateFrameFromConstraints. + /// + public class SimplexTableau { + readonly int rows; + readonly int columns; + readonly Rational[,]/*!*/ m; + + readonly int numInitialVars; + readonly int numSlackVars; + readonly int rhsColumn; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(m != null); + Contract.Invariant(inBasis != null); + Contract.Invariant(basisColumns != null); + } + + readonly ArrayList /*IVariable!*//*!*/ dims; + readonly int[]/*!*/ basisColumns; + readonly int[]/*!*/ inBasis; + bool constructionDone = false; + + void CheckInvariant() { + Contract.Assert(rows == m.GetLength(0)); + Contract.Assert(1 <= columns && columns == m.GetLength(1)); + Contract.Assert(0 <= numInitialVars); + Contract.Assert(0 <= numSlackVars && numSlackVars <= rows); + Contract.Assert(numInitialVars + numSlackVars + 1 == columns); + Contract.Assert(rhsColumn == columns - 1); + Contract.Assert(dims.Count == numInitialVars); + Contract.Assert(basisColumns.Length == rows); + Contract.Assert(inBasis.Length == numInitialVars + numSlackVars); + + bool[] b = new bool[numInitialVars + numSlackVars]; + int numColumnsInBasis = 0; + int numUninitializedRowInfo = 0; + for (int i = 0; i < rows; i++) { + int c = basisColumns[i]; + if (c == rhsColumn) { + // all coefficients in this row are 0 (but the right-hand side may be non-0) + for (int j = 0; j < rhsColumn; j++) { + Contract.Assert(m[i, j].IsZero); + } + numColumnsInBasis++; + } else if (c == -1) { + Contract.Assert(!constructionDone); + numUninitializedRowInfo++; + } else { + // basis column is a column + Contract.Assert(0 <= c && c < numInitialVars + numSlackVars); + // basis column is unique + Contract.Assert(!b[c]); + b[c] = true; + // column is marked as being in basis + Contract.Assert(inBasis[c] == i); + // basis column really is a basis column + for (int j = 0; j < rows; j++) { + if (j == i) { + Contract.Assert(m[j, c].HasValue(1));// == (Rational)new Rational(1))); + } else { + Contract.Assert(m[j, c].IsZero); + } + } + } + } + // no other columns are marked as being in basis + foreach (int i in inBasis) { + if (0 <= i) { + Contract.Assert(i < rows); + numColumnsInBasis++; + } else { + Contract.Assert(i == -1); + } + } + Contract.Assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows); + Contract.Assert(!constructionDone || numUninitializedRowInfo == 0); + } + + /// + /// Constructs a matrix that represents the constraints "constraints", adding slack + /// variables for the inequalities among "constraints". Puts the matrix in canonical + /// form. + /// + /// + [NotDelayed] + public SimplexTableau(ArrayList /*LinearConstraint*//*!*/ constraints) { + Contract.Requires(constraints != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: SimplexTableau constructor called with:"); + foreach (LinearConstraint lc in constraints) + { + Console.WriteLine(" {0}", lc); + } +#endif + // Note: This implementation is not particularly efficient, but it'll do for now. + + ArrayList dims = this.dims = new ArrayList /*IVariable!*/ (); + int slacks = 0; + foreach (LinearConstraint/*!*/ cc in constraints) { + Contract.Assert(cc != null); + foreach (IVariable/*!*/ dim in cc.coefficients.Keys) { + Contract.Assert(dim != null); + if (!dims.Contains(dim)) { + dims.Add(dim); + } + } + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + slacks++; + } + } + + int numInitialVars = this.numInitialVars = dims.Count; + int numSlackVars = this.numSlackVars = slacks; + int rows = this.rows = constraints.Count; + int columns = this.columns = numInitialVars + numSlackVars + 1; + this.m = new Rational[rows, columns]; + this.rhsColumn = columns - 1; + this.basisColumns = new int[rows]; + this.inBasis = new int[columns - 1]; + + //:base(); + + for (int i = 0; i < inBasis.Length; i++) { + inBasis[i] = -1; + } + + // Fill in the matrix + int r = 0; + int iSlack = 0; + foreach (LinearConstraint/*!*/ cc in constraints) { + Contract.Assert(cc != null); + for (int i = 0; i < dims.Count; i++) { + m[r, i] = cc[(IVariable)cce.NonNull(dims[i])]; + } + if (cc.Relation == LinearConstraint.ConstraintRelation.LE) { + m[r, numInitialVars + iSlack] = Rational.ONE; + basisColumns[r] = numInitialVars + iSlack; + inBasis[numInitialVars + iSlack] = r; + iSlack++; + } else { + basisColumns[r] = -1; // special value to communicate to Pivot that basis column i hasn't been set up yet + } + m[r, rhsColumn] = cc.rhs; + r++; + } + Contract.Assert(r == constraints.Count); + Contract.Assert(iSlack == numSlackVars); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: Intermediate tableau state in SimplexTableau constructor:"); + Dump(); +#endif + + // Go through the rows with uninitialized basis columns. These correspond to equality constraints. + // For each one, find an initial variable (non-slack variable) whose column we can make the basis + // column of the row. + for (int i = 0; i < rows; i++) { + if (basisColumns[i] != -1) { + continue; + } + // Find a non-0 column in row i that we can make a basis column. Since rows corresponding + // to equality constraints don't have slack variables and since the pivot operations performed + // by iterations of this loop don't introduce any non-0 coefficients in the slack-variable + // columns of these rows, we only need to look through the columns corresponding to initial + // variables. + for (int j = 0; j < numInitialVars; j++) { + if (m[i, j].IsNonZero) { +#if DEBUG_PRINT + Console.WriteLine("-- About to Pivot({0},{1})", i, j); +#endif + Contract.Assert(inBasis[j] == -1); + Pivot(i, j); +#if DEBUG_PRINT + Console.WriteLine("Tableau after Pivot:"); + Dump(); +#endif + goto SET_UP_NEXT_INBASIS_COLUMN; + } + } + // Check the assertion in the comment above, that is, that columns corresponding to slack variables + // are 0 in this row. + for (int j = numInitialVars; j < rhsColumn; j++) { + Contract.Assert(m[i, j].IsZero); + } + // There is no column in this row that we can put into basis. + basisColumns[i] = rhsColumn; + SET_UP_NEXT_INBASIS_COLUMN: { + } + } + + constructionDone = true; + CheckInvariant(); + } + + public IMutableSet/*!*/ /*IVariable!*/ GetDimensions() { + Contract.Ensures(Contract.Result() != null); + HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ (); + foreach (IVariable/*!*/ dim in dims) { + Contract.Assert(dim != null); + z.Add(dim); + } + return z; + } + + public Rational this[int r, int c] { + get { + return m[r, c]; + } + set { + m[r, c] = value; + } + } + + /// + /// Applies the Pivot Operation on row "r" and column "c". + /// + /// This method can be called when !constructionDone, that is, at a time when not all basis + /// columns have been set up (indicated by -1 in basisColumns). This method helps set up + /// those basis columns. + /// + /// The return value is an undo record that can be used with UnPivot. + /// + /// + /// + public Rational[]/*!*/ Pivot(int r, int c) { + Contract.Ensures(Contract.Result() != null); + Contract.Assert(0 <= r && r < rows); + Contract.Assert(0 <= c && c < columns - 1); + Contract.Assert(m[r, c].IsNonZero); + Contract.Assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0 + Contract.Assert(basisColumns[r] != rhsColumn); // follows from invariant and m[r,c] != 0 + + Rational[] undo = new Rational[rows + 1]; + for (int i = 0; i < rows; i++) { + undo[i] = m[i, c]; + } + + // scale the pivot row + Rational q = m[r, c]; + if (q != Rational.ONE) { + for (int j = 0; j < columns; j++) { + m[r, j] /= q; + } + } + + // subtract a multiple of the pivot row from all other rows + for (int i = 0; i < rows; i++) { + if (i != r) { + q = m[i, c]; + if (q.IsNonZero) { + for (int j = 0; j < columns; j++) { + m[i, j] -= q * m[r, j]; + } + } + } + } + + // update basis information + int prevCol = basisColumns[r]; + undo[rows] = Rational.FromInt(prevCol); + basisColumns[r] = c; + if (prevCol != -1) { + inBasis[prevCol] = -1; + } + inBasis[c] = r; + + return undo; + } + + /// + /// If the last operation applied to the tableau was: + /// undo = Pivot(i,j); + /// then UnPivot(i, j, undo) undoes the pivot operation. + /// Note: This operation is not supported for any call to Pivot before constructionDone + /// is set to true. + /// + /// + /// + /// + void UnPivot(int r, int c, Rational[]/*!*/ undo) { + Contract.Requires(undo != null); + Contract.Assert(0 <= r && r < rows); + Contract.Assert(0 <= c && c < columns - 1); + Contract.Assert(m[r, c].HasValue(1)); + Contract.Assert(undo.Length == rows + 1); + + // add a multiple of the pivot row to all other rows + for (int i = 0; i < rows; i++) { + if (i != r) { + Rational q = undo[i]; + if (q.IsNonZero) { + for (int j = 0; j < columns; j++) { + m[i, j] += q * m[r, j]; + } + } + } + } + + // scale the pivot row + Rational p = undo[r]; + for (int j = 0; j < columns; j++) { + m[r, j] *= p; + } + + // update basis information + int prevCol = undo[rows].AsInteger; + Contract.Assert(prevCol != -1); + basisColumns[r] = prevCol; + inBasis[c] = -1; + inBasis[prevCol] = r; + } + + /// + /// Returns true iff the current basis of the system of constraints modeled by the simplex tableau + /// is feasible. May have a side effect of performing a number of pivot operations on the tableau, + /// but any such pivot operation will be in the columns of slack variables (that is, this routine + /// does not change the set of initial-variable columns in basis). + /// + /// CAVEAT: I have no particular reason to believe that the algorithm used here will terminate. --KRML + /// + /// + public bool IsFeasibleBasis { + get { + // while there is a slack variable in basis whose row has a negative right-hand side + while (true) { + bool feasibleBasis = true; + for (int c = numInitialVars; c < rhsColumn; c++) { + int k = inBasis[c]; + if (0 <= k && k < rhsColumn && m[k, rhsColumn].IsNegative) { + Contract.Assert(m[k, c].HasValue(1)); // c is in basis + // Try to pivot on a different slack variable in this row + for (int i = numInitialVars; i < rhsColumn; i++) { + if (m[k, i].IsNegative) { + Contract.Assert(c != i); // c is in basis, so m[k,c]==1, which is not negative + Pivot(k, i); +#if DEBUG_PRINT + Console.WriteLine("Tableau after Pivot operation on ({0},{1}) in IsFeasibleBasis:", k, i); + Dump(); +#endif + Contract.Assert(inBasis[c] == -1); + Contract.Assert(inBasis[i] == k); + Contract.Assert(m[k, rhsColumn].IsNonNegative); + goto START_ANEW; + } + } + feasibleBasis = false; + } + } + return feasibleBasis; + START_ANEW: + ; + } + } + } + + /// + /// Whether or not all initial variables (the non-slack variables) are in basis) + /// + public bool AllInitialVarsInBasis { + get { + for (int i = 0; i < numInitialVars; i++) { + if (inBasis[i] == -1) { + return false; + } + } + return true; + } + } + + /// + /// Adds as many initial variables as possible to the basis. + /// + /// + public void AddInitialVarsToBasis() { + // while there exists an initial variable not in the basis and not satisfying + // condition 3.4.2.2 in Cousot and Halbwachs, perform a pivot operation + while (true) { + for (int i = 0; i < numInitialVars; i++) { + if (inBasis[i] == -1) { + // initial variable i is not in the basis + for (int j = 0; j < rows; j++) { + if (m[j, i].IsNonZero) { + int k = basisColumns[j]; + if (numInitialVars <= k && k < rhsColumn) { + // slack variable k is in basis for row j + Pivot(j, i); + Contract.Assert(inBasis[k] == -1); + Contract.Assert(inBasis[i] == j && basisColumns[j] == i); + goto START_ANEW; + } + } + } + } + } + // No more initial variables can be moved into basis. + return; + START_ANEW: { + } + } + } + + /// + /// Adds to "lines" the lines implied by initial-variable columns not in basis + /// (see section 3.4.2 of Cousot and Halbwachs), and adds to "constraints" the + /// constraints to exclude those lines (see step 4.2 of section 3.4.3 of + /// Cousot and Halbwachs). + /// + /// + /// + public void ProduceLines(ArrayList /*FrameElement*//*!*/ lines, ArrayList /*LinearConstraint*//*!*/ constraints) { + Contract.Requires(constraints != null); + Contract.Requires(lines != null); + // for every initial variable not in basis + for (int i0 = 0; i0 < numInitialVars; i0++) { + if (inBasis[i0] == -1) { + FrameElement fe = new FrameElement(); + LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + for (int i = 0; i < numInitialVars; i++) { + if (i == i0) { + fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), Rational.ONE); + lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE); + } else if (inBasis[i] != -1) { + // i is a basis column + Contract.Assert(m[inBasis[i], i].HasValue(1)); + Rational val = -m[inBasis[i], i0]; + fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); + lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), val); + } + } + lines.Add(fe); + constraints.Add(lc); + } + } + } + + /// + /// From a feasible point where all initial variables are in the basis, traverses + /// all feasible bases containing all initial variables. For each such basis, adds + /// the vertices to "vertices" and adds to "rays" the extreme rays. See step 4.2 + /// in section 3.4.3 of Cousot and Halbwachs. + /// A more efficient algorithm is found in the paper "An algorithm for + /// determining all extreme points of a convex polytope" by N. E. Dyer and L. G. Proll, + /// Mathematical Programming, 12, 1977. + /// Assumes that the tableau is in a state where all initial variables are in the basis. + /// This method has no net effect on the tableau. + /// Note: Duplicate vertices and rays may be added. + /// + /// + /// + public void TraverseVertices(ArrayList/*!*/ /*FrameElement*/ vertices, ArrayList/*!*/ /*FrameElement*/ rays) { + Contract.Requires(vertices != null); + Contract.Requires(rays != null); + ArrayList /*bool[]*/ basesSeenSoFar = new ArrayList /*bool[]*/ (); + TraverseBases(basesSeenSoFar, vertices, rays); + } + + /// + /// Worker method of TraverseVertices. + /// This method has no net effect on the tableau. + /// + /// + /// + /// + void TraverseBases(ArrayList /*bool[]*//*!*/ basesSeenSoFar, ArrayList /*FrameElement*//*!*/ vertices, ArrayList /*FrameElement*//*!*/ rays) { + Contract.Requires(rays != null); + Contract.Requires(vertices != null); + Contract.Requires(basesSeenSoFar != null); + CheckInvariant(); + + bool[] thisBasis = new bool[numSlackVars]; + for (int i = numInitialVars; i < rhsColumn; i++) { + if (inBasis[i] != -1) { + thisBasis[i - numInitialVars] = true; + } + } + foreach (bool[]/*!*/ basis in basesSeenSoFar) { + Contract.Assert(basis != null); + Contract.Assert(basis.Length == numSlackVars); + for (int i = 0; i < numSlackVars; i++) { + if (basis[i] != thisBasis[i]) { + goto COMPARE_WITH_NEXT_BASIS; + } + } + // thisBasis and basis are the same--that is, basisColumns has been visited before--so + // we don't traverse anything from here + return; + COMPARE_WITH_NEXT_BASIS: { + } + } + // basisColumns has not been seen before; record thisBasis and continue with the traversal here + basesSeenSoFar.Add(thisBasis); + +#if DEBUG_PRINT + Console.Write("TraverseBases, new basis: "); + foreach (bool t in thisBasis) { + Console.Write("{0}", t ? "*" : "."); + } + Console.WriteLine(); + Dump(); +#endif + // Add vertex + FrameElement v = new FrameElement(); + for (int i = 0; i < rows; i++) { + int j = basisColumns[i]; + if (j < numInitialVars) { + v.AddCoordinate((IVariable)cce.NonNull(dims[j]), m[i, rhsColumn]); + } + } +#if DEBUG_PRINT + Console.WriteLine(" Adding vertex: {0}", v); +#endif + vertices.Add(v); + + // Add rays. Traverse all columns corresponding to slack variables that + // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs). + for (int i0 = numInitialVars; i0 < rhsColumn; i0++) { + if (inBasis[i0] != -1) { + // skip those slack-variable columns that are in basis + continue; + } + // check if slack-variable, non-basis column i corresponds to an extreme ray + for (int row = 0; row < rows; row++) { + if (m[row, i0].IsPositive) { + for (int k = numInitialVars; k < rhsColumn; k++) { + if (inBasis[k] != -1 && m[row, k].IsNonZero) { + // does not correspond to an extreme ray + goto CHECK_NEXT_SLACK_VAR; + } + } + } + } + // corresponds to an extreme ray + FrameElement ray = new FrameElement(); + for (int i = 0; i < numInitialVars; i++) { + int j0 = inBasis[i]; + Rational val = -m[j0, i0]; + ray.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); + } +#if DEBUG_PRINT + Console.WriteLine(" Adding ray: {0}", ray); +#endif + rays.Add(ray); + CHECK_NEXT_SLACK_VAR: { + } + } + + // Continue traversal + for (int i = numInitialVars; i < rhsColumn; i++) { + int j = inBasis[i]; + if (j != -1) { + // try moving i out of basis and some other slack-variable column into basis + for (int k = numInitialVars; k < rhsColumn; k++) { + if (inBasis[k] == -1 && m[j, k].IsPositive) { + Rational[] undo = Pivot(j, k); + // check if the new basis is feasible + for (int p = 0; p < rows; p++) { + int c = basisColumns[p]; + if (numInitialVars <= c && c < rhsColumn && m[p, rhsColumn].IsNegative) { + // not feasible + goto AFTER_TRAVERSE; + } + } + TraverseBases(basesSeenSoFar, vertices, rays); + AFTER_TRAVERSE: + UnPivot(j, k, undo); + } + } + } + } + } + + public void Dump() { + // names + Console.Write(" "); + for (int i = 0; i < numInitialVars; i++) { + Console.Write(" {0,4} ", dims[i]); + } + Console.WriteLine(); + // numbers + Console.Write(" "); + for (int i = 0; i < columns; i++) { + if (i == numInitialVars || i == rhsColumn) { + Console.Write("|"); + } + Console.Write(" {0,4}", i); + if (i < rhsColumn && inBasis[i] != -1) { + Console.Write("* "); + Contract.Assert(basisColumns[inBasis[i]] == i); + } else { + Console.Write(" "); + } + } + Console.WriteLine(); + // line + Console.Write(" "); + for (int i = 0; i < columns; i++) { + if (i == numInitialVars || i == rhsColumn) { + Console.Write("+"); + } + Console.Write("---------"); + } + Console.WriteLine(); + + for (int j = 0; j < rows; j++) { + Console.Write("{0,4}: ", basisColumns[j]); + for (int i = 0; i < columns; i++) { + if (i == numInitialVars || i == rhsColumn) { + Console.Write("|"); + } + Console.Write(" {0,4:n1} ", m[j, i]); + } + Console.WriteLine(); + } + } + } +} diff --git a/Source/AIFramework/VariableMap/ConstantAbstraction.cs b/Source/AIFramework/VariableMap/ConstantAbstraction.cs index d8f17a3c..d73fc28b 100644 --- a/Source/AIFramework/VariableMap/ConstantAbstraction.cs +++ b/Source/AIFramework/VariableMap/ConstantAbstraction.cs @@ -1,251 +1,251 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Diagnostics; - //using System.Compiler.Analysis; - using Microsoft.Basetypes; - - /// - /// Represents an invariant over constant variable assignments. - /// - public class ConstantLattice : MicroLattice { - enum Value { - Top, - Bottom, - Constant - } - - private class Elt : Element { - public Value domainValue; - public BigNum constantValue; // valid iff domainValue == Value.Constant - - public Elt(Value v) { - this.domainValue = v; - } - - public Elt(BigNum i) { - this.domainValue = Value.Constant; - this.constantValue = i; - } - - public bool IsConstant { - get { - return this.domainValue == Value.Constant; - } - } - - public BigNum Constant { - get { - return this.constantValue; - } - } // only when IsConstant - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - if (this.IsConstant) - return new Elt(constantValue); - else - return new Elt(domainValue); - } - } - - readonly IIntExprFactory/*!*/ factory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - } - - - public ConstantLattice(IIntExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - this.factory = factory; - // base(); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Top); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Bottom); - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.domainValue == Value.Top; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.domainValue == Value.Bottom; - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); - return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Top; - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); - return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Bottom; - } - - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - return Join(first, second); - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first!= null); - //Contract.Requires(second != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return a.Constant.Equals(b.Constant); - } - - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - return factory.Eq(var, cce.NonNull(GetFoldExpr(element))); - } - - public override IExpr GetFoldExpr(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - Contract.Assert(e.domainValue == Value.Constant); - return factory.Const(e.constantValue); - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - } - - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - - IFunApp nary = e as IFunApp; - if (nary != null) { - if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) { - IList/**//*!*/ args = nary.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for "x == const" or "const == x". - try { - if (arg0 is IVariable) { - BigNum z; - if (Fold(arg1, out z)) { - return new Elt(z); - } - } else if (arg1 is IVariable) { - BigNum z; - if (Fold(arg0, out z)) { - return new Elt(z); - } - } - } catch (System.ArithmeticException) { - // fall through and return Top. (Note, an alternative design may - // consider returning Bottom.) - } - } - } - return Top; - } - - /// - /// Returns true if "expr" represents a constant integer expressions, in which case - /// "z" returns as that integer. Otherwise, returns false, in which case "z" should - /// not be used by the caller. - /// - /// This method throws an System.ArithmeticException in the event that folding the - /// constant expression results in an arithmetic overflow or division by zero. - /// - private bool Fold(IExpr/*!*/ expr, out BigNum z) { - Contract.Requires(expr != null); - IFunApp e = expr as IFunApp; - if (e == null) { - z = BigNum.ZERO; - return false; - } - - if (e.FunctionSymbol is IntSymbol) { - z = ((IntSymbol)e.FunctionSymbol).Value; - return true; - - } else if (e.FunctionSymbol.Equals(Int.Negate)) { - IList/**//*!*/ args = e.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 1); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - - if (Fold(arg0, out z)) { - z = z.Neg; - return true; - } - - } else if (e.Arguments.Count == 2) { - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(e.Arguments[1]); - BigNum z0, z1; - if (Fold(arg0, out z0) && Fold(arg1, out z1)) { - if (e.FunctionSymbol.Equals(Int.Add)) { - z = z0 + z1; - } else if (e.FunctionSymbol.Equals(Int.Sub)) { - z = z0 - z1; - } else if (e.FunctionSymbol.Equals(Int.Mul)) { - z = z0 * z1; - } else if (e.FunctionSymbol.Equals(Int.Div)) { - z = z0 / z1; - } else if (e.FunctionSymbol.Equals(Int.Mod)) { - z = z0 % z1; - } else { - z = BigNum.ZERO; - return false; - } - return true; - } - } - - z = BigNum.ZERO; - return false; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + using Microsoft.Basetypes; + + /// + /// Represents an invariant over constant variable assignments. + /// + public class ConstantLattice : MicroLattice { + enum Value { + Top, + Bottom, + Constant + } + + private class Elt : Element { + public Value domainValue; + public BigNum constantValue; // valid iff domainValue == Value.Constant + + public Elt(Value v) { + this.domainValue = v; + } + + public Elt(BigNum i) { + this.domainValue = Value.Constant; + this.constantValue = i; + } + + public bool IsConstant { + get { + return this.domainValue == Value.Constant; + } + } + + public BigNum Constant { + get { + return this.constantValue; + } + } // only when IsConstant + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + if (this.IsConstant) + return new Elt(constantValue); + else + return new Elt(domainValue); + } + } + + readonly IIntExprFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public ConstantLattice(IIntExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Top); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Bottom); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.domainValue == Value.Top; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.domainValue == Value.Bottom; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); + return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Top; + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant); + return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Bottom; + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first!= null); + //Contract.Requires(second != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return a.Constant.Equals(b.Constant); + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + return factory.Eq(var, cce.NonNull(GetFoldExpr(element))); + } + + public override IExpr GetFoldExpr(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + Contract.Assert(e.domainValue == Value.Constant); + return factory.Const(e.constantValue); + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + + IFunApp nary = e as IFunApp; + if (nary != null) { + if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) { + IList/**//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for "x == const" or "const == x". + try { + if (arg0 is IVariable) { + BigNum z; + if (Fold(arg1, out z)) { + return new Elt(z); + } + } else if (arg1 is IVariable) { + BigNum z; + if (Fold(arg0, out z)) { + return new Elt(z); + } + } + } catch (System.ArithmeticException) { + // fall through and return Top. (Note, an alternative design may + // consider returning Bottom.) + } + } + } + return Top; + } + + /// + /// Returns true if "expr" represents a constant integer expressions, in which case + /// "z" returns as that integer. Otherwise, returns false, in which case "z" should + /// not be used by the caller. + /// + /// This method throws an System.ArithmeticException in the event that folding the + /// constant expression results in an arithmetic overflow or division by zero. + /// + private bool Fold(IExpr/*!*/ expr, out BigNum z) { + Contract.Requires(expr != null); + IFunApp e = expr as IFunApp; + if (e == null) { + z = BigNum.ZERO; + return false; + } + + if (e.FunctionSymbol is IntSymbol) { + z = ((IntSymbol)e.FunctionSymbol).Value; + return true; + + } else if (e.FunctionSymbol.Equals(Int.Negate)) { + IList/**//*!*/ args = e.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 1); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + + if (Fold(arg0, out z)) { + z = z.Neg; + return true; + } + + } else if (e.Arguments.Count == 2) { + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(e.Arguments[1]); + BigNum z0, z1; + if (Fold(arg0, out z0) && Fold(arg1, out z1)) { + if (e.FunctionSymbol.Equals(Int.Add)) { + z = z0 + z1; + } else if (e.FunctionSymbol.Equals(Int.Sub)) { + z = z0 - z1; + } else if (e.FunctionSymbol.Equals(Int.Mul)) { + z = z0 * z1; + } else if (e.FunctionSymbol.Equals(Int.Div)) { + z = z0 / z1; + } else if (e.FunctionSymbol.Equals(Int.Mod)) { + z = z0 % z1; + } else { + z = BigNum.ZERO; + return false; + } + return true; + } + } + + z = BigNum.ZERO; + return false; + } + } +} diff --git a/Source/AIFramework/VariableMap/ConstantExpressions.cs b/Source/AIFramework/VariableMap/ConstantExpressions.cs index fcf49b25..185c700e 100644 --- a/Source/AIFramework/VariableMap/ConstantExpressions.cs +++ b/Source/AIFramework/VariableMap/ConstantExpressions.cs @@ -1,538 +1,538 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - - ///////////////////////////////////////////////////////////////////////////////// - // The Abstract domain for determining "constant" expressions - // i.e. It determines which expression are statically binded - ///////////////////////////////////////////////////////////////////////////////// -/* -using System; - -namespace Microsoft.AbstractInterpretationFramework -{ - using Microsoft.Contracts; - using System.Collections.Generic; - using Microsoft.AbstractInterpretationFramework; - - /// - /// This is an abstract domain for inferring constant expressions - /// - - public class ConstantExpressions : Lattice - { - /// - /// An abstract element is made of two maps: - /// + A map from variables to expressions \cup top ( i.e. for each variable, the expression it is binded ) - /// + A map from variables to set of variabes ( i.e. for each variable, the set of variables that depends on its value ) - /// - private class AbstractElement: Element - { - private Dictionary variableBindings; - private Dictionary> variableDependences; - - static private AbstractElement! bottom; - static public Element! Bottom - { - get - { - if(bottom == null) - { - bottom = new AbstractElement(); - bottom.variableBindings = null; - bottom.variableDependences = null; - } - assert bottom.variableBindings == null && bottom.variableDependences == null; - return bottom; - } - } - - static public Element! Top - { - get - { - return new AbstractElement(); - } - } - - AbstractElement() - { - this.variableBindings = new Dictionary(); - this.variableDependences = new Dictionary>(); - } - - /// - /// Our abstract element is top if and only if it has any constraint on variables - /// - public bool IsTop - { - get - { - return this.variableBindings.Keys.Count == 0 && this.variableDependences.Keys.Count == 0; - } - } - - /// - /// Our abstract element is bottom if and only if the maps are null - /// - public bool IsBottom - { - get - { - assert (this.variableBindings == null) <==> (this.variableDependences == null); +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + + ///////////////////////////////////////////////////////////////////////////////// + // The Abstract domain for determining "constant" expressions + // i.e. It determines which expression are statically binded + ///////////////////////////////////////////////////////////////////////////////// +/* +using System; + +namespace Microsoft.AbstractInterpretationFramework +{ + using Microsoft.Contracts; + using System.Collections.Generic; + using Microsoft.AbstractInterpretationFramework; + + /// + /// This is an abstract domain for inferring constant expressions + /// + + public class ConstantExpressions : Lattice + { + /// + /// An abstract element is made of two maps: + /// + A map from variables to expressions \cup top ( i.e. for each variable, the expression it is binded ) + /// + A map from variables to set of variabes ( i.e. for each variable, the set of variables that depends on its value ) + /// + private class AbstractElement: Element + { + private Dictionary variableBindings; + private Dictionary> variableDependences; + + static private AbstractElement! bottom; + static public Element! Bottom + { + get + { + if(bottom == null) + { + bottom = new AbstractElement(); + bottom.variableBindings = null; + bottom.variableDependences = null; + } + assert bottom.variableBindings == null && bottom.variableDependences == null; + return bottom; + } + } + + static public Element! Top + { + get + { + return new AbstractElement(); + } + } + + AbstractElement() + { + this.variableBindings = new Dictionary(); + this.variableDependences = new Dictionary>(); + } + + /// + /// Our abstract element is top if and only if it has any constraint on variables + /// + public bool IsTop + { + get + { + return this.variableBindings.Keys.Count == 0 && this.variableDependences.Keys.Count == 0; + } + } + + /// + /// Our abstract element is bottom if and only if the maps are null + /// + public bool IsBottom + { + get + { + assert (this.variableBindings == null) <==> (this.variableDependences == null); return this.variableBindings == null && this.variableDependences == null; - } - } - - /// - /// The pointwise join... - /// - public static AbstractElement! Join(AbstractElement! left, AbstractElement! right) - { + } + } + + /// + /// The pointwise join... + /// + public static AbstractElement! Join(AbstractElement! left, AbstractElement! right) + { AbstractElement! result = new AbstractElement(); - - // Put all the variables in the left - foreach(IVariable! var in left.variableBindings.Keys) - { - BindExpr leftVal = left.variableBindings[var]; - assert leftVal != null; - - BindExpr rightVal = right.variableBindings[var]; - - if(rightVal== null) // the expression is not there - { + + // Put all the variables in the left + foreach(IVariable! var in left.variableBindings.Keys) + { + BindExpr leftVal = left.variableBindings[var]; + assert leftVal != null; + + BindExpr rightVal = right.variableBindings[var]; + + if(rightVal== null) // the expression is not there + { result.variableBindings.Add(var, leftVal); - } - else // both abstract elements have a definition for the variable.... - { - result.variableBindings.Add(var, BindExpr.Join(leftVal, rightVal)); - } - } - - // Put all the variables in the right - foreach(IVariable! var in right.variableBindings.Keys) - { - BindExpr rightVal = right.variableBindings[var]; - assert rightVal != null; - - BindExpr leftVal = left.variableBindings[var]; - - if(rightVal== null) // the expression is not there - { + } + else // both abstract elements have a definition for the variable.... + { + result.variableBindings.Add(var, BindExpr.Join(leftVal, rightVal)); + } + } + + // Put all the variables in the right + foreach(IVariable! var in right.variableBindings.Keys) + { + BindExpr rightVal = right.variableBindings[var]; + assert rightVal != null; + + BindExpr leftVal = left.variableBindings[var]; + + if(rightVal== null) // the expression is not there + { result.variableBindings.Add(var, rightVal); - } - else // both abstract elements have a definition for the variable.... - { - result.variableBindings.Add(var, BindExpr.Join(rightVal, leftVal)); - } - } - - // Join the dependencies... - foreach(IVariable! var in left.variableDependences.Keys) - { - List dependencies = left.variableDependences[var]; - List dup = new List(dependencies); - - result.variableDependences.Add(var, dup); - } - - foreach(IVariable! var in right.variableDependences.Keys) - { - if(result.variableDependences.ContainsKey(var)) - { - List dependencies = result.variableDependences[var]; - dependencies.AddRange(right.variableDependences[var]); - } - else - { - List dependencies = right.variableDependences[var]; - List dup = new List(dependencies); - - result.variableDependences.Add(var, dup); - } - } - - // Normalize... i.e. for the variables such thas they point to an unknown expression (top) we have to update also their values - result.Normalize(); - - return result; - } - - - /// - /// Normalize the current abstract element, in that it propagetes the "dynamic" information throughtout the abstract element - /// - public void Normalize() - { - if(this.IsBottom) - return; - if(this.IsTop) - return; - assert this.variableBindings != null; - - bool atFixpoint = false; - - while(!atFixpoint) - { - atFixpoint = true; // guess that we've got the fixpoint... - - foreach(IVariable x in this.variableBindings.Keys) - { - if(this.variableBindings[x].IsTop) // It means that the variable is tied to a dynamic expression - { - foreach(IVariable y in this.variableDependences[x]) // The all the variables that depend on x are also dynamic... - { - assert x != y; // A variable cannot depend on itself... - if(!this.variableBindings[y].IsTop) - { - this.variableBindings[y] = BindExpr.Top; - atFixpoint = false; // the assumption that we were at the fixpoint was false, we have still to propagate some information... - } - } - } - } - } - } - - /// - /// The pointwise meet... - /// - public static AbstractElement! Meet(AbstractElement! left, AbstractElement! right) - { - AbstractElement! result = new AbstractElement(); - - // Put the variables that are both in left and right - foreach(IVariable var in left.variableBindings.Keys) - { - if(right.variableBindings.ContainsKey(var)) - { - result.variableBindings.Add(var, BindExpr.Meet(left.variableBindings[var], right.variableBindings[var])); - } - } - - // Intersect the dependencies - foreach(IVariable var in result.variableBindings.Keys) - { - List depLeft = left.variableDependences[var]; - List depRight = right.variableDependences[var]; - - // Intersect the two sets + } + else // both abstract elements have a definition for the variable.... + { + result.variableBindings.Add(var, BindExpr.Join(rightVal, leftVal)); + } + } + + // Join the dependencies... + foreach(IVariable! var in left.variableDependences.Keys) + { + List dependencies = left.variableDependences[var]; + List dup = new List(dependencies); + + result.variableDependences.Add(var, dup); + } + + foreach(IVariable! var in right.variableDependences.Keys) + { + if(result.variableDependences.ContainsKey(var)) + { + List dependencies = result.variableDependences[var]; + dependencies.AddRange(right.variableDependences[var]); + } + else + { + List dependencies = right.variableDependences[var]; + List dup = new List(dependencies); + + result.variableDependences.Add(var, dup); + } + } + + // Normalize... i.e. for the variables such thas they point to an unknown expression (top) we have to update also their values + result.Normalize(); + + return result; + } + + + /// + /// Normalize the current abstract element, in that it propagetes the "dynamic" information throughtout the abstract element + /// + public void Normalize() + { + if(this.IsBottom) + return; + if(this.IsTop) + return; + assert this.variableBindings != null; + + bool atFixpoint = false; + + while(!atFixpoint) + { + atFixpoint = true; // guess that we've got the fixpoint... + + foreach(IVariable x in this.variableBindings.Keys) + { + if(this.variableBindings[x].IsTop) // It means that the variable is tied to a dynamic expression + { + foreach(IVariable y in this.variableDependences[x]) // The all the variables that depend on x are also dynamic... + { + assert x != y; // A variable cannot depend on itself... + if(!this.variableBindings[y].IsTop) + { + this.variableBindings[y] = BindExpr.Top; + atFixpoint = false; // the assumption that we were at the fixpoint was false, we have still to propagate some information... + } + } + } + } + } + } + + /// + /// The pointwise meet... + /// + public static AbstractElement! Meet(AbstractElement! left, AbstractElement! right) + { + AbstractElement! result = new AbstractElement(); + + // Put the variables that are both in left and right + foreach(IVariable var in left.variableBindings.Keys) + { + if(right.variableBindings.ContainsKey(var)) + { + result.variableBindings.Add(var, BindExpr.Meet(left.variableBindings[var], right.variableBindings[var])); + } + } + + // Intersect the dependencies + foreach(IVariable var in result.variableBindings.Keys) + { + List depLeft = left.variableDependences[var]; + List depRight = right.variableDependences[var]; + + // Intersect the two sets result.variableDependences.Add(var, depLeft); - foreach(IVariable v in depRight) - { - if(!result.variableDependences.ContainsKey(v)) - { + foreach(IVariable v in depRight) + { + if(!result.variableDependences.ContainsKey(v)) + { result.variableDependences.Remove(v); - } - } - } - - // Now we remove the dependencies with variables not in variableBindings + } + } + } + + // Now we remove the dependencies with variables not in variableBindings List! varsToRemove = new List(); - - foreach(IVariable var in result. - - - } - - /// - /// Clone the current abstract element - /// - public override Element! Clone() - { - AbstractElement cloned = new AbstractElement(); - foreach(IVariable var in this.variableBindings.Keys) - { - cloned.variableBindings.Add(var, this.variableBindings[var]); - } - - foreach(IVariable var in this.variableDependences.Keys) - { - List dependingVars = this.variableDependences[var]; - List clonedDependingVars = new List(dependingVars); + + foreach(IVariable var in result. + + + } + + /// + /// Clone the current abstract element + /// + public override Element! Clone() + { + AbstractElement cloned = new AbstractElement(); + foreach(IVariable var in this.variableBindings.Keys) + { + cloned.variableBindings.Add(var, this.variableBindings[var]); + } + + foreach(IVariable var in this.variableDependences.Keys) + { + List dependingVars = this.variableDependences[var]; + List clonedDependingVars = new List(dependingVars); cloned.variableDependences.Add(var, clonedDependingVars); - } - } - - /// - /// Return the variables that have a binding - /// - public override ICollection! FreeVariables() - { - List vars = new List(this.variableBindings.Keys); - - return vars; - } - - public override string! ToString() - { + } + } + + /// + /// Return the variables that have a binding + /// + public override ICollection! FreeVariables() + { + List vars = new List(this.variableBindings.Keys); + + return vars; + } + + public override string! ToString() + { string! retString = ""; - retString += "Bindings"; - - foreach(IVariable var in this.variableBindings.Keys) - { - string! toAdd = var.ToString() + " -> " + this.variableBindings[var]; - retString += toAdd + ","; - } - - retString += "\nDependencies"; - foreach(IVariable var in this.variableDependences.Keys) - { - string! toAdd = var.ToString() + " -> " + this.variableDependences[var]; - retString += toAdd + ","; - } - - return retString; - } - } - - public override Element! Top - { - get - { - return AbstractElement.Top; - } - } - - public override Element! Bottom - { - get - { - return AbstractElement.Bottom; - } - } - - public override bool IsTop(Element! e) - { - assert e is AbstractElement; - AbstractElement! absElement = (AbstractElement) e; - - return absElement.IsTop; - } - - public override bool IsBottom(Element! e) - { - assert e is AbstractElement; - AbstractElement absElement = (AbstractElement) e; - return absElement.IsBottom; - } - - /// - /// Perform the pointwise join of the two abstract elements - /// - public override Element! NontrivialJoin(Element! a, Element! b) - { - assert a is AbstractElement; - assert b is AbstractElement; - - AbstractElement! left = (AbstractElement!) a; - AbstractElement! right = (AbstractElement!) b; - - return AbstractElement.Join(left, right); - } - - /// - /// Perform the pointwise meet of two abstract elements - /// - public override Element! NontrivialMeet(Element! a, Element!b) - { - assert a is AbstractElement; - assert b is AbstractElement; - - AbstractElement! left = (AbstractElement!) a; - AbstractElement! right = (AbstractElement!) b; - - return AbstractElement.Meet(left, right); - } - - - } - - /// - /// A wrapper in order to have the algebraic datatype BindExpr := IExpr | Top - /// - abstract class BindExpr - { - /// - /// True iff this expression is instance of BindExprTop - /// - public bool IsTop - { - get - { - return this is BindExprTop; - } - } - - static public BindExpr Top - { - get - { - return BindExprTop.UniqueTop; - } - } - - /// - /// True iff this expression is instance of BindExprBottom - /// - public bool IsBottom - { - get - { - return this is BindExprBottom; - } - } - - static public BindExpr Bottom - { - get - { - return BindExprBottom.UniqueBottom; - } - } - - public static BindExpr! Join(BindExpr! left, BindExpr! right) - { - if(left.IsTop || right.IsTop) - { - return BindExpr.Top; - } - else if(left.IsBottom) - { - return right; - } - else if(right.IsBottom) - { - return left; - } - else if(left.EmbeddedExpr != right.EmbeddedExpr) - { - return BindExpr.Top; - } - else // left.EmbeddedExpr == right.EmbeddedExpr - { - return left; - } - } - - public static BindExpr! Meet(BindExpr! left, BindExpr! right) - { - if(left.IsTop) - { - return right; - } - else if(right.IsTop) - { - return right; - } - else if(left.IsBottom || right.IsBottom) - { - return BindExpr.Bottom; - } - else if(left.EmbeddedExpr != right.EmbeddedExpr) - { - return BindExpr.Bottom; - } - else // left.EmbeddedExpr == right.EmbeddedExpr - { - return left; - } - } - - abstract public IExpr! EmbeddedExpr - { - get; - } - - } - - /// - /// A wrapper for an integer - /// - class Expr : BindExpr - { - private IExpr! exp; - - public Expr(IExpr! exp) - { - this.exp = exp; - } - - override public IExpr! EmbeddedExpr - { - get - { - return this.exp; - } - } - - public override string! ToString() - { - return this.exp.ToString(); - } - } - - /// - /// The dynamic expression - /// - class BindExprTop : BindExpr - { - private BindExprTop top = new BindExprTop(); - static public BindExprTop! UniqueTop - { - get - { - return this.top; - } - } - - private BindExprTop() {} - - override public IExpr! EmbeddedExpr - { - get - { - assert false; // If we get there, we have an error - } - } - - public override string! ToString() - { - return ""; - } - } - - /// - /// The unreachable expression - /// - class BindExprBottom : BindExpr - { - private BindExprBottom! bottom = new BindExprBottom(); - static public BindExprBottom! UniqueBottom - { - get - { - return this.bottom; - } - } - - private BindExprBottom() {} - - override public IExpr! EmbeddedExpr - { - get - { - assert false; - } - } - - public override string! ToString() - { - return ""; - } - } - -} // end namespace Microsoft.AbstractInterpretationFramework + retString += "Bindings"; + + foreach(IVariable var in this.variableBindings.Keys) + { + string! toAdd = var.ToString() + " -> " + this.variableBindings[var]; + retString += toAdd + ","; + } + + retString += "\nDependencies"; + foreach(IVariable var in this.variableDependences.Keys) + { + string! toAdd = var.ToString() + " -> " + this.variableDependences[var]; + retString += toAdd + ","; + } + + return retString; + } + } + + public override Element! Top + { + get + { + return AbstractElement.Top; + } + } + + public override Element! Bottom + { + get + { + return AbstractElement.Bottom; + } + } + + public override bool IsTop(Element! e) + { + assert e is AbstractElement; + AbstractElement! absElement = (AbstractElement) e; + + return absElement.IsTop; + } + + public override bool IsBottom(Element! e) + { + assert e is AbstractElement; + AbstractElement absElement = (AbstractElement) e; + return absElement.IsBottom; + } + + /// + /// Perform the pointwise join of the two abstract elements + /// + public override Element! NontrivialJoin(Element! a, Element! b) + { + assert a is AbstractElement; + assert b is AbstractElement; + + AbstractElement! left = (AbstractElement!) a; + AbstractElement! right = (AbstractElement!) b; + + return AbstractElement.Join(left, right); + } + + /// + /// Perform the pointwise meet of two abstract elements + /// + public override Element! NontrivialMeet(Element! a, Element!b) + { + assert a is AbstractElement; + assert b is AbstractElement; + + AbstractElement! left = (AbstractElement!) a; + AbstractElement! right = (AbstractElement!) b; + + return AbstractElement.Meet(left, right); + } + + + } + + /// + /// A wrapper in order to have the algebraic datatype BindExpr := IExpr | Top + /// + abstract class BindExpr + { + /// + /// True iff this expression is instance of BindExprTop + /// + public bool IsTop + { + get + { + return this is BindExprTop; + } + } + + static public BindExpr Top + { + get + { + return BindExprTop.UniqueTop; + } + } + + /// + /// True iff this expression is instance of BindExprBottom + /// + public bool IsBottom + { + get + { + return this is BindExprBottom; + } + } + + static public BindExpr Bottom + { + get + { + return BindExprBottom.UniqueBottom; + } + } + + public static BindExpr! Join(BindExpr! left, BindExpr! right) + { + if(left.IsTop || right.IsTop) + { + return BindExpr.Top; + } + else if(left.IsBottom) + { + return right; + } + else if(right.IsBottom) + { + return left; + } + else if(left.EmbeddedExpr != right.EmbeddedExpr) + { + return BindExpr.Top; + } + else // left.EmbeddedExpr == right.EmbeddedExpr + { + return left; + } + } + + public static BindExpr! Meet(BindExpr! left, BindExpr! right) + { + if(left.IsTop) + { + return right; + } + else if(right.IsTop) + { + return right; + } + else if(left.IsBottom || right.IsBottom) + { + return BindExpr.Bottom; + } + else if(left.EmbeddedExpr != right.EmbeddedExpr) + { + return BindExpr.Bottom; + } + else // left.EmbeddedExpr == right.EmbeddedExpr + { + return left; + } + } + + abstract public IExpr! EmbeddedExpr + { + get; + } + + } + + /// + /// A wrapper for an integer + /// + class Expr : BindExpr + { + private IExpr! exp; + + public Expr(IExpr! exp) + { + this.exp = exp; + } + + override public IExpr! EmbeddedExpr + { + get + { + return this.exp; + } + } + + public override string! ToString() + { + return this.exp.ToString(); + } + } + + /// + /// The dynamic expression + /// + class BindExprTop : BindExpr + { + private BindExprTop top = new BindExprTop(); + static public BindExprTop! UniqueTop + { + get + { + return this.top; + } + } + + private BindExprTop() {} + + override public IExpr! EmbeddedExpr + { + get + { + assert false; // If we get there, we have an error + } + } + + public override string! ToString() + { + return ""; + } + } + + /// + /// The unreachable expression + /// + class BindExprBottom : BindExpr + { + private BindExprBottom! bottom = new BindExprBottom(); + static public BindExprBottom! UniqueBottom + { + get + { + return this.bottom; + } + } + + private BindExprBottom() {} + + override public IExpr! EmbeddedExpr + { + get + { + assert false; + } + } + + public override string! ToString() + { + return ""; + } + } + +} // end namespace Microsoft.AbstractInterpretationFramework */ \ No newline at end of file diff --git a/Source/AIFramework/VariableMap/DynamicTypeLattice.cs b/Source/AIFramework/VariableMap/DynamicTypeLattice.cs index 78bd61a0..edda7c1e 100644 --- a/Source/AIFramework/VariableMap/DynamicTypeLattice.cs +++ b/Source/AIFramework/VariableMap/DynamicTypeLattice.cs @@ -1,511 +1,511 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Diagnostics; - //using System.Compiler.Analysis; - //using Microsoft.SpecSharp.Collections; - using System.Diagnostics.Contracts; - - /// - /// Represents information about the dynamic type of a variable. In particular, for a - /// variable "v", represents either Bottom, "typeof(v)==T" for some type T, or a set - /// of constraints "typeof(v) subtype of T_i for some number of T_i's. - /// - public class DynamicTypeLattice : MicroLattice { - enum What { - Bottom, - Exact, - Bounds - } - - private class Elt : Element { - // Representation: - // - Bottom is represented by: what==What.Bottom - // - An exact type T is represented by: what==What.Exact && ty==T - // - A set of type constraints T0, T1, T2, ..., T{n-1} is represented by: - // -- if n==0: what==What.Bounds && ty==null && manyBounds==null - // -- if n==1: what==What.Bounds && ty==T0 && manyBounds==null - // -- if n>=2: what==What.Bounds && ty==null && - // manyBounds!=null && manyBounds.Length==n && - // manyBounds[0]==T0 && manyBounds[1]==T1 && ... && manyBounds[n-1]==T{n-1} - // The reason for keeping the one-and-only bound in "ty" in case n==1 is to try - // to prevent the need for allocating a whole array of bounds, since 1 bound is - // bound to be common. - // In the representation, there are no redundant bounds in manyBounds. - // It is assumed that the types can can occur as exact bounds form a single-inheritance - // hierarchy. That is, if T0 and T1 are types that can occur as exact types, then - // there is no v such that typeof(v) is a subtype of both T0 and T1, unless T0 and T1 are - // the same type. - public readonly What what; - public readonly IExpr ty; - [Rep] - public readonly IExpr[] manyBounds; - [ContractInvariantMethod] - void ObjectInvariant() { - - Contract.Invariant(what != What.Bottom || ty == null && manyBounds == null); - Contract.Invariant(manyBounds == null || what == What.Bounds); - Contract.Invariant(manyBounds == null || Contract.ForAll(0, manyBounds.Length, i => manyBounds[i] != null)); - } - public Elt(What what, IExpr ty) { - Contract.Requires(what != What.Bottom || ty == null); - Contract.Requires(what != What.Exact || ty != null); - this.what = what; - this.ty = ty; - this.manyBounds = null; - } - - public Elt(IExpr[]/*!*/ bounds) { - Contract.Requires(bounds != null); - Contract.Requires(Contract.ForAll(0, bounds.Length, i => bounds[i] != null)); - this.what = What.Bounds; - if (bounds.Length == 0) { - this.ty = null; - this.manyBounds = null; - } else if (bounds.Length == 1) { - this.ty = bounds[0]; - this.manyBounds = null; - } else { - this.ty = null; - this.manyBounds = bounds; - } - } - - /// - /// Constructs an Elt with "n" bounds, namely the n non-null values of the "bounds" list. - /// - [NotDelayed] - public Elt(ArrayList /*IExpr*//*!*/ bounds, int n) { - Contract.Requires(bounds != null); - Contract.Requires(0 <= n && n <= bounds.Count); - this.what = What.Bounds; - if (n > 1) { - this.manyBounds = new IExpr[n]; - } - int k = 0; - foreach (IExpr bound in bounds) { - if (bound != null) { - Contract.Assert(k != n); - if (n == 1) { - Contract.Assert(this.ty == null); - this.ty = bound; - } else { - Contract.Assume(manyBounds != null); - manyBounds[k] = bound; - } - k++; - } - } - Contract.Assert(k == n); - } - - public int BoundsCount { - get { - Contract.Ensures(0 <= Contract.Result()); - if (manyBounds != null) { - return manyBounds.Length; - } else if (ty != null) { - return 1; - } else { - return 0; - } - } - } - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - if (this.manyBounds != null) - return new Elt(this.manyBounds); - else - return new Elt(this.what, this.ty); - } - } - - readonly ITypeExprFactory/*!*/ factory; - readonly IPropExprFactory/*!*/ propFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - Contract.Invariant(propFactory != null); - } - - - public DynamicTypeLattice(ITypeExprFactory/*!*/ factory, IPropExprFactory/*!*/ propFactory) { - Contract.Requires(propFactory != null); - Contract.Requires(factory != null); - this.factory = factory; - this.propFactory = propFactory; - // base(); - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(What.Bounds, null); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(What.Bottom, null); - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.what == What.Bounds && e.ty == null && e.manyBounds == null; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.what == What.Bottom; - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); - if (a.what == What.Exact && b.what == What.Exact) { - Contract.Assert(a.ty != null && b.ty != null); - if (factory.IsTypeEqual(a.ty, b.ty)) { - return a; - } else { - return new Elt(What.Bounds, factory.JoinTypes(a.ty, b.ty)); - } - } - - // The result is going to be a Bounds, since at least one of the operands is a Bounds. - Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top - int n = a.BoundsCount + b.BoundsCount; - - // Special case: a and b each has exactly one bound - if (n == 2) { - Contract.Assert(a.ty != null && b.ty != null); - IExpr join = factory.JoinTypes(a.ty, b.ty); - Contract.Assert(join != null); - if (join == a.ty && a.what == What.Bounds) { - return a; - } else if (join == b.ty && b.what == What.Bounds) { - return b; - } else { - return new Elt(What.Bounds, join); - } - } - - // General case - ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); // final size - ArrayList /*IExpr!*/ result = new ArrayList /*IExpr!*/ (n); // a guess at the size, but could be as big as size(a)*size(b) - if (a.ty != null) { - allBounds.Add(a.ty); - } else { - allBounds.AddRange(cce.NonNull(a.manyBounds)); - } - int bStart = allBounds.Count; - if (b.ty != null) { - allBounds.Add(b.ty); - } else { - allBounds.AddRange(cce.NonNull(b.manyBounds)); - } - // compute the join of each pair, putting non-redundant joins into "result" - for (int i = 0; i < bStart; i++) { - IExpr/*!*/ aBound = cce.NonNull((IExpr/*!*/)allBounds[i]); - for (int j = bStart; j < allBounds.Count; j++) { - IExpr/*!*/ bBound = (IExpr/*!*/)cce.NonNull(allBounds[j]); - - IExpr/*!*/ join = factory.JoinTypes(aBound, bBound); - Contract.Assert(join != null); - - int k = 0; - while (k < result.Count) { - IExpr/*!*/ r = (IExpr/*!*/)cce.NonNull(result[k]); - if (factory.IsSubType(join, r)) { - // "join" is more restrictive than a bound already placed in "result", - // so toss out "join" and compute the join of the next pair - goto NEXT_PAIR; - } else if (factory.IsSubType(r, join)) { - // "join" is less restrictive than a bound already placed in "result", - // so toss out that old bound - result.RemoveAt(k); - } else { - k++; - } - } - result.Add(join); - NEXT_PAIR: { - } - } - } - return new Elt(result, result.Count); - } - - - public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); - - if (a.what == What.Exact && b.what == What.Exact) { - Contract.Assert(a.ty != null && b.ty != null); - if (factory.IsTypeEqual(a.ty, b.ty)) { - return a; - } else { - return Bottom; - } - - } else if (a.what == What.Exact || b.what == What.Exact) { - // One is Bounds, the other Exact. Make b be the Bounds one. - if (a.what == What.Bounds) { - Elt tmp = a; - a = b; - b = tmp; - } - Contract.Assert(a.what == What.Exact && b.what == What.Bounds); - // Check the exact type against all bounds. If the exact type is more restrictive - // than all bounds, then return it. If some bound is not met by the exact type, return - // bottom. - Contract.Assert(a.ty != null); - if (b.ty != null && !factory.IsSubType(a.ty, b.ty)) { - return Bottom; - } - if (b.manyBounds != null) { - foreach (IExpr/*!*/ bound in b.manyBounds) { - Contract.Assert(bound != null); - if (!factory.IsSubType(a.ty, bound)) { - return Bottom; - } - } - } - return a; - } else { - // Both operands are Bounds. - Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); - - // Take all the bounds, but prune those bounds that follow from others. - Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top - int n = a.BoundsCount + b.BoundsCount; - // Special case: a and b each has exactly one bound - if (n == 2) { - Contract.Assert(a.ty != null && b.ty != null); - if (factory.IsSubType(a.ty, b.ty)) { - // a is more restrictive - return a; - } else if (factory.IsSubType(b.ty, a.ty)) { - // b is more restrictive - return b; - } else { - IExpr[]/*!*/ bounds = new IExpr[2]; - bounds[0] = a.ty; - bounds[1] = b.ty; - return new Elt(bounds); - } - } - - // General case - ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); - if (a.ty != null) { - allBounds.Add(a.ty); - } else { - allBounds.AddRange(cce.NonNull(a.manyBounds)); - } - int bStart = allBounds.Count; - if (b.ty != null) { - allBounds.Add(b.ty); - } else { - allBounds.AddRange(cce.NonNull(b.manyBounds)); - } - for (int i = 0; i < bStart; i++) { - IExpr/*!*/ aBound = cce.NonNull((IExpr)allBounds[i]); - for (int j = bStart; j < allBounds.Count; j++) { - IExpr bBound = (IExpr/*! Wouldn't the non-null typing in the original Spec# code had made bBound never null, - * thus negating the need for the continue statement?*/ - )allBounds[j]; - if (bBound == null) { - continue; - } else if (factory.IsSubType(aBound, bBound)) { - // a is more restrictive, so blot out the b bound - allBounds[j] = null; - n--; - } else if (factory.IsSubType(bBound, aBound)) { - // b is more restrictive, so blot out the a bound - allBounds[i] = null; - n--; - goto CONTINUE_OUTER_LOOP; - } - } - CONTINUE_OUTER_LOOP: { - } - } - Contract.Assert(1 <= n); - return new Elt(allBounds, n); - } - } - - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - return Join(first, second); - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first != null); - //Contract.Requires(second != null); - Elt/*!*/ a = (Elt/*!*/)cce.NonNull(first); - Elt/*!*/ b = (Elt/*!*/)cce.NonNull(second); - Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); - - if (a.what == What.Exact && b.what == What.Exact) { - Contract.Assert(a.ty != null && b.ty != null); - return factory.IsTypeEqual(a.ty, b.ty); - } else if (b.what == What.Exact) { - return false; - } else if (a.what == What.Exact) { - Contract.Assert(a.ty != null); - if (b.ty != null) { - return factory.IsSubType(a.ty, b.ty); - } else { - return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); - } - } else { - Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); - Contract.Assert(a.ty != null || a.manyBounds != null); // a precondition is that a is not Top - Contract.Assert(b.ty != null || b.manyBounds != null); // a precondition is that b is not Top - // Return true iff: for each constraint in b, there is a stricter constraint in a. - if (a.ty != null && b.ty != null) { - return factory.IsSubType(a.ty, b.ty); - } else if (a.ty != null) { - return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); - } else if (b.ty != null) { - return Contract.Exists(a.manyBounds, bound => factory.IsSubType(bound, b.ty)); - } else { - return Contract.ForAll(b.manyBounds, bBound => Contract.Exists(a.manyBounds, aBound => factory.IsSubType(aBound, bBound))); - } - } - } - - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - switch (e.what) { - case What.Bottom: - return propFactory.False; - case What.Exact: - return factory.IsExactlyA(var, cce.NonNull(e.ty)); - case What.Bounds: - if (e.ty == null && e.manyBounds == null) { - return propFactory.True; - } else if (e.ty != null) { - return factory.IsA(var, e.ty); - } else { - IExpr/*!*/ p = factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds)[0]); - for (int i = 1; i < e.manyBounds.Length; i++) { - p = propFactory.And(p, factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds[i]))); - } - return p; - } - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - throw new System.Exception(); - } - } - - public override IExpr GetFoldExpr(Element/*!*/ e) { - //Contract.Requires(e != null); - // cannot fold into an expression that can be substituted for the variable - return null; - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t - if (isEq && factory.IsTypeConstant(arg0)) { - // swap the arguments - IExpr/*!*/ tmp = arg0; - arg0 = arg1; - arg1 = tmp; - } else if (!factory.IsTypeConstant(arg1)) { - return false; - } - IFunApp typeofExpr = arg0 as IFunApp; - if (typeofExpr != null && - typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { - Contract.Assert(typeofExpr.Arguments.Count == 1); - if (typeofExpr.Arguments[0] is IVariable) { - // we have a match - return true; - } - } - } - return false; - } - - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - IFunApp nary = e as IFunApp; - if (nary != null) { - - bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { - IList/**//*!*/ args = nary.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t - if (isEq && factory.IsTypeConstant(arg0)) { - // swap the arguments - IExpr/*!*/ tmp = arg0; - arg0 = arg1; - arg1 = tmp; - } else if (!factory.IsTypeConstant(arg1)) { - return Top; - } - IFunApp typeofExpr = arg0 as IFunApp; - if (typeofExpr != null && - typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { - Contract.Assert(typeofExpr.Arguments.Count == 1); - if (typeofExpr.Arguments[0] is IVariable) { - // we have a match - return new Elt(isEq ? What.Exact : What.Bounds, arg1); - } - } - } - } - return Top; - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + //using Microsoft.SpecSharp.Collections; + using System.Diagnostics.Contracts; + + /// + /// Represents information about the dynamic type of a variable. In particular, for a + /// variable "v", represents either Bottom, "typeof(v)==T" for some type T, or a set + /// of constraints "typeof(v) subtype of T_i for some number of T_i's. + /// + public class DynamicTypeLattice : MicroLattice { + enum What { + Bottom, + Exact, + Bounds + } + + private class Elt : Element { + // Representation: + // - Bottom is represented by: what==What.Bottom + // - An exact type T is represented by: what==What.Exact && ty==T + // - A set of type constraints T0, T1, T2, ..., T{n-1} is represented by: + // -- if n==0: what==What.Bounds && ty==null && manyBounds==null + // -- if n==1: what==What.Bounds && ty==T0 && manyBounds==null + // -- if n>=2: what==What.Bounds && ty==null && + // manyBounds!=null && manyBounds.Length==n && + // manyBounds[0]==T0 && manyBounds[1]==T1 && ... && manyBounds[n-1]==T{n-1} + // The reason for keeping the one-and-only bound in "ty" in case n==1 is to try + // to prevent the need for allocating a whole array of bounds, since 1 bound is + // bound to be common. + // In the representation, there are no redundant bounds in manyBounds. + // It is assumed that the types can can occur as exact bounds form a single-inheritance + // hierarchy. That is, if T0 and T1 are types that can occur as exact types, then + // there is no v such that typeof(v) is a subtype of both T0 and T1, unless T0 and T1 are + // the same type. + public readonly What what; + public readonly IExpr ty; + [Rep] + public readonly IExpr[] manyBounds; + [ContractInvariantMethod] + void ObjectInvariant() { + + Contract.Invariant(what != What.Bottom || ty == null && manyBounds == null); + Contract.Invariant(manyBounds == null || what == What.Bounds); + Contract.Invariant(manyBounds == null || Contract.ForAll(0, manyBounds.Length, i => manyBounds[i] != null)); + } + public Elt(What what, IExpr ty) { + Contract.Requires(what != What.Bottom || ty == null); + Contract.Requires(what != What.Exact || ty != null); + this.what = what; + this.ty = ty; + this.manyBounds = null; + } + + public Elt(IExpr[]/*!*/ bounds) { + Contract.Requires(bounds != null); + Contract.Requires(Contract.ForAll(0, bounds.Length, i => bounds[i] != null)); + this.what = What.Bounds; + if (bounds.Length == 0) { + this.ty = null; + this.manyBounds = null; + } else if (bounds.Length == 1) { + this.ty = bounds[0]; + this.manyBounds = null; + } else { + this.ty = null; + this.manyBounds = bounds; + } + } + + /// + /// Constructs an Elt with "n" bounds, namely the n non-null values of the "bounds" list. + /// + [NotDelayed] + public Elt(ArrayList /*IExpr*//*!*/ bounds, int n) { + Contract.Requires(bounds != null); + Contract.Requires(0 <= n && n <= bounds.Count); + this.what = What.Bounds; + if (n > 1) { + this.manyBounds = new IExpr[n]; + } + int k = 0; + foreach (IExpr bound in bounds) { + if (bound != null) { + Contract.Assert(k != n); + if (n == 1) { + Contract.Assert(this.ty == null); + this.ty = bound; + } else { + Contract.Assume(manyBounds != null); + manyBounds[k] = bound; + } + k++; + } + } + Contract.Assert(k == n); + } + + public int BoundsCount { + get { + Contract.Ensures(0 <= Contract.Result()); + if (manyBounds != null) { + return manyBounds.Length; + } else if (ty != null) { + return 1; + } else { + return 0; + } + } + } + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + if (this.manyBounds != null) + return new Elt(this.manyBounds); + else + return new Elt(this.what, this.ty); + } + } + + readonly ITypeExprFactory/*!*/ factory; + readonly IPropExprFactory/*!*/ propFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + Contract.Invariant(propFactory != null); + } + + + public DynamicTypeLattice(ITypeExprFactory/*!*/ factory, IPropExprFactory/*!*/ propFactory) { + Contract.Requires(propFactory != null); + Contract.Requires(factory != null); + this.factory = factory; + this.propFactory = propFactory; + // base(); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(What.Bounds, null); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(What.Bottom, null); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.what == What.Bounds && e.ty == null && e.manyBounds == null; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.what == What.Bottom; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + if (a.what == What.Exact && b.what == What.Exact) { + Contract.Assert(a.ty != null && b.ty != null); + if (factory.IsTypeEqual(a.ty, b.ty)) { + return a; + } else { + return new Elt(What.Bounds, factory.JoinTypes(a.ty, b.ty)); + } + } + + // The result is going to be a Bounds, since at least one of the operands is a Bounds. + Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top + int n = a.BoundsCount + b.BoundsCount; + + // Special case: a and b each has exactly one bound + if (n == 2) { + Contract.Assert(a.ty != null && b.ty != null); + IExpr join = factory.JoinTypes(a.ty, b.ty); + Contract.Assert(join != null); + if (join == a.ty && a.what == What.Bounds) { + return a; + } else if (join == b.ty && b.what == What.Bounds) { + return b; + } else { + return new Elt(What.Bounds, join); + } + } + + // General case + ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); // final size + ArrayList /*IExpr!*/ result = new ArrayList /*IExpr!*/ (n); // a guess at the size, but could be as big as size(a)*size(b) + if (a.ty != null) { + allBounds.Add(a.ty); + } else { + allBounds.AddRange(cce.NonNull(a.manyBounds)); + } + int bStart = allBounds.Count; + if (b.ty != null) { + allBounds.Add(b.ty); + } else { + allBounds.AddRange(cce.NonNull(b.manyBounds)); + } + // compute the join of each pair, putting non-redundant joins into "result" + for (int i = 0; i < bStart; i++) { + IExpr/*!*/ aBound = cce.NonNull((IExpr/*!*/)allBounds[i]); + for (int j = bStart; j < allBounds.Count; j++) { + IExpr/*!*/ bBound = (IExpr/*!*/)cce.NonNull(allBounds[j]); + + IExpr/*!*/ join = factory.JoinTypes(aBound, bBound); + Contract.Assert(join != null); + + int k = 0; + while (k < result.Count) { + IExpr/*!*/ r = (IExpr/*!*/)cce.NonNull(result[k]); + if (factory.IsSubType(join, r)) { + // "join" is more restrictive than a bound already placed in "result", + // so toss out "join" and compute the join of the next pair + goto NEXT_PAIR; + } else if (factory.IsSubType(r, join)) { + // "join" is less restrictive than a bound already placed in "result", + // so toss out that old bound + result.RemoveAt(k); + } else { + k++; + } + } + result.Add(join); + NEXT_PAIR: { + } + } + } + return new Elt(result, result.Count); + } + + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + + if (a.what == What.Exact && b.what == What.Exact) { + Contract.Assert(a.ty != null && b.ty != null); + if (factory.IsTypeEqual(a.ty, b.ty)) { + return a; + } else { + return Bottom; + } + + } else if (a.what == What.Exact || b.what == What.Exact) { + // One is Bounds, the other Exact. Make b be the Bounds one. + if (a.what == What.Bounds) { + Elt tmp = a; + a = b; + b = tmp; + } + Contract.Assert(a.what == What.Exact && b.what == What.Bounds); + // Check the exact type against all bounds. If the exact type is more restrictive + // than all bounds, then return it. If some bound is not met by the exact type, return + // bottom. + Contract.Assert(a.ty != null); + if (b.ty != null && !factory.IsSubType(a.ty, b.ty)) { + return Bottom; + } + if (b.manyBounds != null) { + foreach (IExpr/*!*/ bound in b.manyBounds) { + Contract.Assert(bound != null); + if (!factory.IsSubType(a.ty, bound)) { + return Bottom; + } + } + } + return a; + } else { + // Both operands are Bounds. + Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); + + // Take all the bounds, but prune those bounds that follow from others. + Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top + int n = a.BoundsCount + b.BoundsCount; + // Special case: a and b each has exactly one bound + if (n == 2) { + Contract.Assert(a.ty != null && b.ty != null); + if (factory.IsSubType(a.ty, b.ty)) { + // a is more restrictive + return a; + } else if (factory.IsSubType(b.ty, a.ty)) { + // b is more restrictive + return b; + } else { + IExpr[]/*!*/ bounds = new IExpr[2]; + bounds[0] = a.ty; + bounds[1] = b.ty; + return new Elt(bounds); + } + } + + // General case + ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); + if (a.ty != null) { + allBounds.Add(a.ty); + } else { + allBounds.AddRange(cce.NonNull(a.manyBounds)); + } + int bStart = allBounds.Count; + if (b.ty != null) { + allBounds.Add(b.ty); + } else { + allBounds.AddRange(cce.NonNull(b.manyBounds)); + } + for (int i = 0; i < bStart; i++) { + IExpr/*!*/ aBound = cce.NonNull((IExpr)allBounds[i]); + for (int j = bStart; j < allBounds.Count; j++) { + IExpr bBound = (IExpr/*! Wouldn't the non-null typing in the original Spec# code had made bBound never null, + * thus negating the need for the continue statement?*/ + )allBounds[j]; + if (bBound == null) { + continue; + } else if (factory.IsSubType(aBound, bBound)) { + // a is more restrictive, so blot out the b bound + allBounds[j] = null; + n--; + } else if (factory.IsSubType(bBound, aBound)) { + // b is more restrictive, so blot out the a bound + allBounds[i] = null; + n--; + goto CONTINUE_OUTER_LOOP; + } + } + CONTINUE_OUTER_LOOP: { + } + } + Contract.Assert(1 <= n); + return new Elt(allBounds, n); + } + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + Elt/*!*/ a = (Elt/*!*/)cce.NonNull(first); + Elt/*!*/ b = (Elt/*!*/)cce.NonNull(second); + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + + if (a.what == What.Exact && b.what == What.Exact) { + Contract.Assert(a.ty != null && b.ty != null); + return factory.IsTypeEqual(a.ty, b.ty); + } else if (b.what == What.Exact) { + return false; + } else if (a.what == What.Exact) { + Contract.Assert(a.ty != null); + if (b.ty != null) { + return factory.IsSubType(a.ty, b.ty); + } else { + return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); + } + } else { + Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); + Contract.Assert(a.ty != null || a.manyBounds != null); // a precondition is that a is not Top + Contract.Assert(b.ty != null || b.manyBounds != null); // a precondition is that b is not Top + // Return true iff: for each constraint in b, there is a stricter constraint in a. + if (a.ty != null && b.ty != null) { + return factory.IsSubType(a.ty, b.ty); + } else if (a.ty != null) { + return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); + } else if (b.ty != null) { + return Contract.Exists(a.manyBounds, bound => factory.IsSubType(bound, b.ty)); + } else { + return Contract.ForAll(b.manyBounds, bBound => Contract.Exists(a.manyBounds, aBound => factory.IsSubType(aBound, bBound))); + } + } + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + switch (e.what) { + case What.Bottom: + return propFactory.False; + case What.Exact: + return factory.IsExactlyA(var, cce.NonNull(e.ty)); + case What.Bounds: + if (e.ty == null && e.manyBounds == null) { + return propFactory.True; + } else if (e.ty != null) { + return factory.IsA(var, e.ty); + } else { + IExpr/*!*/ p = factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds)[0]); + for (int i = 1; i < e.manyBounds.Length; i++) { + p = propFactory.And(p, factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds[i]))); + } + return p; + } + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + throw new System.Exception(); + } + } + + public override IExpr GetFoldExpr(Element/*!*/ e) { + //Contract.Requires(e != null); + // cannot fold into an expression that can be substituted for the variable + return null; + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t + if (isEq && factory.IsTypeConstant(arg0)) { + // swap the arguments + IExpr/*!*/ tmp = arg0; + arg0 = arg1; + arg1 = tmp; + } else if (!factory.IsTypeConstant(arg1)) { + return false; + } + IFunApp typeofExpr = arg0 as IFunApp; + if (typeofExpr != null && + typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { + Contract.Assert(typeofExpr.Arguments.Count == 1); + if (typeofExpr.Arguments[0] is IVariable) { + // we have a match + return true; + } + } + } + return false; + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + IFunApp nary = e as IFunApp; + if (nary != null) { + + bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { + IList/**//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t + if (isEq && factory.IsTypeConstant(arg0)) { + // swap the arguments + IExpr/*!*/ tmp = arg0; + arg0 = arg1; + arg1 = tmp; + } else if (!factory.IsTypeConstant(arg1)) { + return Top; + } + IFunApp typeofExpr = arg0 as IFunApp; + if (typeofExpr != null && + typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) { + Contract.Assert(typeofExpr.Arguments.Count == 1); + if (typeofExpr.Arguments[0] is IVariable) { + // we have a match + return new Elt(isEq ? What.Exact : What.Bounds, arg1); + } + } + } + } + return Top; + } + + } +} diff --git a/Source/AIFramework/VariableMap/Intervals.cs b/Source/AIFramework/VariableMap/Intervals.cs index 0bf82cf4..98bf9007 100644 --- a/Source/AIFramework/VariableMap/Intervals.cs +++ b/Source/AIFramework/VariableMap/Intervals.cs @@ -1,871 +1,871 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -//using System.Compiler.Analysis; -using Microsoft.AbstractInterpretationFramework.Collections; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; - -///////////////////////////////////////////////////////////////////////////////// -// An implementation of the interval abstract domain -///////////////////////////////////////////////////////////////////////////////// - -namespace Microsoft.AbstractInterpretationFramework { - public class IntervalLattice : MicroLattice { - readonly ILinearExprFactory/*!*/ factory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - } - - - public IntervalLattice(ILinearExprFactory/*!*/ factory) { - Contract.Requires(factory != null); - this.factory = factory; - // base(); - } - - public override bool UnderstandsBasicArithmetics { - get { - return true; - } - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - - return IntervalElement.Top; - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - - return IntervalElement.Bottom; - } - } - - /// - /// The paramter is the top? - /// - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - IntervalElement interval = (IntervalElement)element; - - return interval.IsTop(); - } - - /// - /// The parameter is the bottom? - /// - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - IntervalElement interval = (IntervalElement)element; - - return interval.IsBottom(); - } - - /// - /// The classic, pointwise, join of intervals - /// - public override Element/*!*/ NontrivialJoin(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); - - ExtendedInt inf = ExtendedInt.Inf(leftInterval.Inf, rightInterval.Inf); - ExtendedInt sup = ExtendedInt.Sup(leftInterval.Sup, rightInterval.Sup); - - IntervalElement/*!*/ join = IntervalElement.Factory(inf, sup); - - return join; - } - - /// - /// The classic, pointwise, meet of intervals - /// - public override Element/*!*/ NontrivialMeet(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); - - ExtendedInt inf = ExtendedInt.Sup(leftInterval.Inf, rightInterval.Inf); - ExtendedInt sup = ExtendedInt.Inf(leftInterval.Sup, rightInterval.Sup); - - return IntervalElement.Factory(inf, sup); - } - - - /// - /// The very simple widening of intervals, to be improved with thresholds - /// left is the PREVIOUS value in the iterations and right is the NEW one - /// - public override Element/*!*/ Widen(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ prevInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ nextInterval = (IntervalElement/*!*/)cce.NonNull(right); - - ExtendedInt inf = nextInterval.Inf < prevInterval.Inf ? ExtendedInt.MinusInfinity : prevInterval.Inf; - ExtendedInt sup = nextInterval.Sup > prevInterval.Sup ? ExtendedInt.PlusInfinity : prevInterval.Sup; - - IntervalElement widening = IntervalElement.Factory(inf, sup); - - return widening; - } - - - /// - /// Return true iff the interval left is containted in right - /// - protected override bool AtMost(Element/*!*/ left, Element/*!*/ right) { - //Contract.Requires(right != null); - //Contract.Requires(left != null); - IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); - IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); - - if (leftInterval.IsBottom() || rightInterval.IsTop()) - return true; - - return rightInterval.Inf <= leftInterval.Inf && leftInterval.Sup <= rightInterval.Sup; - } - - /// - /// Return just null - /// - public override IExpr GetFoldExpr(Element/*!*/ element) { - //Contract.Requires(element != null); - return null; - } - - /// - /// return a predicate inf "\leq x and x "\leq" sup (if inf [or sup] is not oo) - /// - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - IntervalElement/*!*/ interval = (IntervalElement/*!*/)cce.NonNull(element); - IExpr lowerBound = null; - IExpr upperBound = null; - - if (!(interval.Inf is InfinitaryInt)) { - IExpr constant = this.factory.Const(interval.Inf.Value); - lowerBound = this.factory.AtMost(constant, var); // inf <= var - } - if (!(interval.Sup is InfinitaryInt)) { - IExpr constant = this.factory.Const(interval.Sup.Value); - upperBound = this.factory.AtMost(var, constant); // var <= inf - } - - if (lowerBound != null && upperBound != null) - return this.factory.And(lowerBound, upperBound); // inf <= var && var <= sup - else - if (lowerBound != null) - return lowerBound; - else - if (upperBound != null) - return upperBound; - else // If we reach this point, both lowerBound and upperBound are null, i.e. we have no bounds on var, so we return simply true... - return this.factory.True; - } - - /// - /// For the moment consider just equalities. Other case must be considered - /// - public override bool Understands(IFunctionSymbol/*!*/ f, IList /* - /// Evaluate the predicate passed as input according the semantics of intervals - /// - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - Contract.Ensures(Contract.Result() != null); - return this.EvaluatePredicateWithState(pred, null); - } - - /// - /// Evaluate the predicate passed as input according the semantics of intervals and the given state. - /// Right now just basic arithmetic operations are supported. A future extension may consider an implementation of boolean predicates - /// - public override Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ pred, IFunctionalMap/* Var -> Element */ state) { - //Contract.Requires(pred != null); - Contract.Ensures(Contract.Result() != null); - if (pred is IFunApp) { - IFunApp fun = (IFunApp)pred; - if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality - { - IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - if (leftArg is IVariable) { - return Eval(rightArg, state); - } else if (rightArg is IVariable) { - return Eval(leftArg, state); - } - } - } - // otherwise we simply return Top - return IntervalElement.Top; - } - - /// - /// Evaluate the expression (that is assured to be an arithmetic expression, in the state passed as a parameter - /// - private IntervalElement/*!*/ Eval(IExpr/*!*/ exp, IFunctionalMap/* Var -> Element */ state) { - Contract.Requires((exp != null)); - Contract.Ensures(Contract.Result() != null); - - IntervalElement/*!*/ retVal = (IntervalElement/*!*/)cce.NonNull(Top); - - // Eval the expression by structural induction - - - if (exp is IVariable && state != null) // A variable - { - object lookup = state[exp]; - if (lookup is IntervalElement) - retVal = (IntervalElement)lookup; - else { - retVal = (IntervalElement)Top; - } - } else if (exp is IFunApp) { - IFunApp fun = (IFunApp)exp; - - if (fun.FunctionSymbol is IntSymbol) // An integer - { - IntSymbol intSymb = (IntSymbol)fun.FunctionSymbol; - BigNum val = intSymb.Value; - - retVal = IntervalElement.Factory(val); - } else if (fun.FunctionSymbol.Equals(Int.Negate)) // An unary minus - { - IExpr/*!*/ arg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IntervalElement/*!*/ argEval = Eval(arg, state); - Contract.Assert(argEval != null); - IntervalElement/*!*/ zero = IntervalElement.Factory(BigNum.ZERO); - Contract.Assert(zero != null); - - retVal = zero - argEval; - } else if (fun.Arguments.Count == 2) { - IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - - IntervalElement/*!*/ leftVal = Eval(left, state); - Contract.Assert(leftVal != null); - IntervalElement/*!*/ rightVal = Eval(right, state); - Contract.Assert(rightVal != null); - - if (fun.FunctionSymbol.Equals(Int.Add)) - retVal = leftVal + rightVal; - else if (fun.FunctionSymbol.Equals(Int.Sub)) - retVal = leftVal - rightVal; - else if (fun.FunctionSymbol.Equals(Int.Mul)) - retVal = leftVal * rightVal; - else if (fun.FunctionSymbol.Equals(Int.Div)) - retVal = leftVal / rightVal; - else if (fun.FunctionSymbol.Equals(Int.Mod)) - retVal = leftVal % rightVal; - } - } - - return retVal; - } - - /// - /// Inner class standing for an interval on integers, possibly unbounded - /// - private class IntervalElement : Element { - protected static readonly IntervalElement/*!*/ TopInterval = new IntervalElement(new MinusInfinity(), new PlusInfinity()); // Top = [-oo , +oo] - protected static readonly IntervalElement/*!*/ BottomInterval = new IntervalElement(new PlusInfinity(), new MinusInfinity()); // Bottom = [+oo, -oo] - - private readonly ExtendedInt/*!*/ inf; - private readonly ExtendedInt/*!*/ sup; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(inf != null); - Contract.Invariant(sup != null); - } - - public ExtendedInt/*!*/ Inf { - get { - Contract.Ensures(Contract.Result() != null); - - return inf; - } - } - - public ExtendedInt/*!*/ Sup { - get { - Contract.Ensures(Contract.Result() != null); - - return sup; - } - } - - // Construct the inteval [val, val] - protected IntervalElement(BigNum val) { - this.inf = this.sup = ExtendedInt.Factory(val); - // base(); - } - - // Construct the interval [inf, sup] - protected IntervalElement(BigNum infInt, BigNum supInt) { - this.inf = ExtendedInt.Factory(infInt); - this.sup = ExtendedInt.Factory(supInt); - // base(); // to please the compiler... - } - - protected IntervalElement(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - this.inf = inf; - this.sup = sup; - // base(); - } - - // Construct an Interval - public static IntervalElement/*!*/ Factory(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires((sup != null)); - Contract.Requires((inf != null)); - Contract.Ensures(Contract.Result() != null); - if (inf is MinusInfinity && sup is PlusInfinity) - return Top; - if (inf > sup) - return Bottom; - // otherwise... - return new IntervalElement(inf, sup); - } - - public static IntervalElement/*!*/ Factory(BigNum i) { - Contract.Ensures(Contract.Result() != null); - return new IntervalElement(i); - } - - public static IntervalElement/*!*/ Factory(BigNum inf, BigNum sup) { - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ i = ExtendedInt.Factory(inf); - ExtendedInt/*!*/ s = ExtendedInt.Factory(sup); - - return Factory(i, s); - } - - static public IntervalElement/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - - return TopInterval; - } - } - - static public IntervalElement/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - - return BottomInterval; - } - } - - public bool IsTop() { - return this.inf is MinusInfinity && this.sup is PlusInfinity; - } - - public bool IsBottom() { - return this.inf > this.sup; - } - - #region Below are the arithmetic operations lifted to intervals - - // Addition - public static IntervalElement/*!*/ operator +(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ inf = a.inf + b.inf; - Contract.Assert(inf != null); - ExtendedInt/*!*/ sup = a.sup + b.sup; - Contract.Assert(sup != null); - - return Factory(inf, sup); - } - - // Subtraction - public static IntervalElement/*!*/ operator -(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ inf = a.inf - b.sup; - Contract.Assert(inf != null); - - ExtendedInt/*!*/ sup = a.sup - b.inf; - Contract.Assert(sup != null); - IntervalElement/*!*/ sub = Factory(inf, sup); - Contract.Assert(sub != null); - - return sub; - } - - // Multiplication - public static IntervalElement/*!*/ operator *(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ infinf = a.inf * b.inf; - Contract.Assert(infinf != null); - ExtendedInt/*!*/ infsup = a.inf * b.sup; - Contract.Assert(infsup != null); - ExtendedInt/*!*/ supinf = a.sup * b.inf; - Contract.Assert(supinf != null); - ExtendedInt/*!*/ supsup = a.sup * b.sup; - Contract.Assert(supsup != null); - - ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); - Contract.Assert(inf != null); - ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); - Contract.Assert(sup != null); - - return Factory(inf, sup); - } - - // Division - public static IntervalElement/*!*/ operator /(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.inf.IsZero && b.sup.IsZero) // Check division by zero - return IntervalElement.Top; - - ExtendedInt/*!*/ infinf = a.inf / b.inf; - Contract.Assert(infinf != null); - ExtendedInt/*!*/ infsup = a.inf / b.sup; - Contract.Assert(infsup != null); - ExtendedInt/*!*/ supinf = a.sup / b.inf; - Contract.Assert(supinf != null); - ExtendedInt/*!*/ supsup = a.sup / b.sup; - Contract.Assert(supsup != null); - - ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); - Contract.Assert(inf != null); - ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); - Contract.Assert(sup != null); - - return Factory(inf, sup); - } - - // Division - public static IntervalElement/*!*/ operator %(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.inf.IsZero && b.sup.IsZero) // Check division by zero - return IntervalElement.Top; - - ExtendedInt/*!*/ infinf = a.inf % b.inf; - Contract.Assert(infinf != null); - ExtendedInt/*!*/ infsup = a.inf % b.sup; - Contract.Assert(infsup != null); - ExtendedInt/*!*/ supinf = a.sup % b.inf; - Contract.Assert(supinf != null); - ExtendedInt/*!*/ supsup = a.sup % b.sup; - Contract.Assert(supsup != null); - - ExtendedInt inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); - ExtendedInt sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); - - return Factory(inf, sup); - } - - #endregion - - #region Overriden methods - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - // Real copying should not be needed because intervals are immutable? - return this; - /* - int valInf = this.inf.Value; - int valSup = this.sup.Value; - - ExtendedInt clonedInf = ExtendedInt.Factory(valInf); - ExtendedInt clonedSup = ExtendedInt.Factory(valSup); - - return Factory(clonedInf, clonedSup); - */ - } - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "[" + this.inf + ", " + this.sup + "]"; - } - - #endregion - } - } - - - /// The interface for an extended integer - /// - [ContractClass(typeof(ExtendedIntContracts))] - abstract class ExtendedInt { - private static readonly PlusInfinity/*!*/ cachedPlusInf = new PlusInfinity(); - private static readonly MinusInfinity/*!*/ cachedMinusInf = new MinusInfinity(); - - static public ExtendedInt/*!*/ PlusInfinity { - get { - Contract.Ensures(Contract.Result() != null); - - return cachedPlusInf; - } - } - - static public ExtendedInt/*!*/ MinusInfinity { - get { - Contract.Ensures(Contract.Result() != null); - - return cachedMinusInf; - } - } - - public abstract BigNum Value { - get; - } - - public abstract int Signum { - get; - } - - public bool IsZero { - get { - return Signum == 0; - } - } - - public bool IsPositive { - get { - return Signum > 0; - } - } - - public bool IsNegative { - get { - return Signum < 0; - } - } - - - #region Below are the extensions of arithmetic operations on extended integers - - // Addition - public static ExtendedInt/*!*/ operator +(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return b; - } else { - return ExtendedInt.Factory(a.Value + b.Value); - } - } - - // Subtraction - public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return UnaryMinus(b); - } else { - return ExtendedInt.Factory(a.Value - b.Value); - } - } - - // Unary minus - public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a) { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - // BUGBUG: Some compiler error prevents the unary minus operator from being used - return UnaryMinus(a); - } - - // Unary minus - public static ExtendedInt/*!*/ UnaryMinus(ExtendedInt/*!*/ a) { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a is PlusInfinity) - return cachedMinusInf; - if (a is MinusInfinity) - return cachedPlusInf; - else // a is a PureInteger - return new PureInteger(-a.Value); - } - - // Multiplication - public static ExtendedInt/*!*/ operator *(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (a.IsZero) { - return a; - } else if (b.IsZero) { - return b; - } else if (a is InfinitaryInt) { - if (b.IsPositive) { - return a; - } else { - return UnaryMinus(a); - } - } else if (b is InfinitaryInt) { - if (a.IsPositive) { - return b; - } else { - return UnaryMinus(b); - } - } else { - return ExtendedInt.Factory(a.Value * b.Value); - } - } - - // Division - public static ExtendedInt/*!*/ operator /(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.IsZero) { - return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; - } - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return b; - } else { - return ExtendedInt.Factory(a.Value / b.Value); - } - } - - // Modulo - public static ExtendedInt/*!*/ operator %(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - if (b.IsZero) { - return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; - } - if (a is InfinitaryInt) { - return a; - } else if (b is InfinitaryInt) { - return b; - } else { - return ExtendedInt.Factory(a.Value % b.Value); - } - } - - #endregion - - #region Inf and Sup operations - - public abstract int CompareTo(ExtendedInt/*!*/ that); - - public static bool operator <(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - return inf.CompareTo(sup) < 0; - } - - public static bool operator >(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - return inf.CompareTo(sup) > 0; - } - - public static bool operator <=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - return inf.CompareTo(sup) <= 0; - } - - public static bool operator >=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - Contract.Requires(inf != null && sup != null); - return inf.CompareTo(sup) >= 0; - } - - public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - Contract.Ensures(Contract.Result() != null); - if (inf < sup) - return inf; - else - return sup; - } - - public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { - Contract.Requires(d != null); - Contract.Requires(c != null); - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ infab = Inf(a, b); - Contract.Assert(infab != null); - ExtendedInt/*!*/ infcd = Inf(c, d); - Contract.Assert(infcd != null); - - return Inf(infab, infcd); - } - - public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { - Contract.Requires(sup != null); - Contract.Requires(inf != null); - Contract.Ensures(Contract.Result() != null); - if (inf > sup) - return inf; - else - return sup; - } - - public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { - Contract.Requires(d != null); - Contract.Requires(c != null); - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - ExtendedInt/*!*/ supab = Sup(a, b); - Contract.Assert(supab != null); - ExtendedInt/*!*/ supcd = Sup(c, d); - Contract.Assert(supcd != null); - - return Sup(supab, supcd); - } - - #endregion - - // Return the ExtendedInt corresponding to the value - public static ExtendedInt/*!*/ Factory(BigNum val) { - Contract.Ensures(Contract.Result() != null); - return new PureInteger(val); - } - } - [ContractClassFor(typeof(ExtendedInt))] - abstract class ExtendedIntContracts : ExtendedInt { - public override int CompareTo(ExtendedInt that) { - Contract.Requires(that != null); - throw new NotImplementedException(); - } - } - - // Stands for a normal (finite) integer x - class PureInteger : ExtendedInt { - public PureInteger(BigNum i) { - this.val = i; - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return this.Value.ToString(); - } - - private BigNum val; - public override BigNum Value { - get { - return this.val; - } - } - - public override int Signum { - get { - return val.Signum; - } - } - - public override int CompareTo(ExtendedInt/*!*/ that) { - //Contract.Requires(that != null); - if (that is PlusInfinity) - return -1; - else if (that is PureInteger) - return this.Value.CompareTo(that.Value); - else // then that is a MinusInfinity - return 1; - } - } - - abstract class InfinitaryInt : ExtendedInt { - public override BigNum Value { - get { - throw new InvalidOperationException(); - } - } - } - - class PlusInfinity : InfinitaryInt { - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "+oo"; - } - - public override int Signum { - get { - return 1; - } - } - - public override int CompareTo(ExtendedInt/*!*/ that) { - //Contract.Requires(that != null); - if (that is PlusInfinity) - return 0; - else - return 1; - } - } - - class MinusInfinity : InfinitaryInt { - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return "-oo"; - } - - public override int Signum { - get { - return -1; - } - } - - public override int CompareTo(ExtendedInt/*!*/ that) { - //Contract.Requires(that != null); - if (that is MinusInfinity) - return 0; - else - return -1; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +//using System.Compiler.Analysis; +using Microsoft.AbstractInterpretationFramework.Collections; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; + +///////////////////////////////////////////////////////////////////////////////// +// An implementation of the interval abstract domain +///////////////////////////////////////////////////////////////////////////////// + +namespace Microsoft.AbstractInterpretationFramework { + public class IntervalLattice : MicroLattice { + readonly ILinearExprFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public IntervalLattice(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + public override bool UnderstandsBasicArithmetics { + get { + return true; + } + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + + return IntervalElement.Top; + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + + return IntervalElement.Bottom; + } + } + + /// + /// The paramter is the top? + /// + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + IntervalElement interval = (IntervalElement)element; + + return interval.IsTop(); + } + + /// + /// The parameter is the bottom? + /// + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + IntervalElement interval = (IntervalElement)element; + + return interval.IsBottom(); + } + + /// + /// The classic, pointwise, join of intervals + /// + public override Element/*!*/ NontrivialJoin(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); + + ExtendedInt inf = ExtendedInt.Inf(leftInterval.Inf, rightInterval.Inf); + ExtendedInt sup = ExtendedInt.Sup(leftInterval.Sup, rightInterval.Sup); + + IntervalElement/*!*/ join = IntervalElement.Factory(inf, sup); + + return join; + } + + /// + /// The classic, pointwise, meet of intervals + /// + public override Element/*!*/ NontrivialMeet(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); + + ExtendedInt inf = ExtendedInt.Sup(leftInterval.Inf, rightInterval.Inf); + ExtendedInt sup = ExtendedInt.Inf(leftInterval.Sup, rightInterval.Sup); + + return IntervalElement.Factory(inf, sup); + } + + + /// + /// The very simple widening of intervals, to be improved with thresholds + /// left is the PREVIOUS value in the iterations and right is the NEW one + /// + public override Element/*!*/ Widen(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ prevInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ nextInterval = (IntervalElement/*!*/)cce.NonNull(right); + + ExtendedInt inf = nextInterval.Inf < prevInterval.Inf ? ExtendedInt.MinusInfinity : prevInterval.Inf; + ExtendedInt sup = nextInterval.Sup > prevInterval.Sup ? ExtendedInt.PlusInfinity : prevInterval.Sup; + + IntervalElement widening = IntervalElement.Factory(inf, sup); + + return widening; + } + + + /// + /// Return true iff the interval left is containted in right + /// + protected override bool AtMost(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(right); + + if (leftInterval.IsBottom() || rightInterval.IsTop()) + return true; + + return rightInterval.Inf <= leftInterval.Inf && leftInterval.Sup <= rightInterval.Sup; + } + + /// + /// Return just null + /// + public override IExpr GetFoldExpr(Element/*!*/ element) { + //Contract.Requires(element != null); + return null; + } + + /// + /// return a predicate inf "\leq x and x "\leq" sup (if inf [or sup] is not oo) + /// + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + IntervalElement/*!*/ interval = (IntervalElement/*!*/)cce.NonNull(element); + IExpr lowerBound = null; + IExpr upperBound = null; + + if (!(interval.Inf is InfinitaryInt)) { + IExpr constant = this.factory.Const(interval.Inf.Value); + lowerBound = this.factory.AtMost(constant, var); // inf <= var + } + if (!(interval.Sup is InfinitaryInt)) { + IExpr constant = this.factory.Const(interval.Sup.Value); + upperBound = this.factory.AtMost(var, constant); // var <= inf + } + + if (lowerBound != null && upperBound != null) + return this.factory.And(lowerBound, upperBound); // inf <= var && var <= sup + else + if (lowerBound != null) + return lowerBound; + else + if (upperBound != null) + return upperBound; + else // If we reach this point, both lowerBound and upperBound are null, i.e. we have no bounds on var, so we return simply true... + return this.factory.True; + } + + /// + /// For the moment consider just equalities. Other case must be considered + /// + public override bool Understands(IFunctionSymbol/*!*/ f, IList /* + /// Evaluate the predicate passed as input according the semantics of intervals + /// + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + Contract.Ensures(Contract.Result() != null); + return this.EvaluatePredicateWithState(pred, null); + } + + /// + /// Evaluate the predicate passed as input according the semantics of intervals and the given state. + /// Right now just basic arithmetic operations are supported. A future extension may consider an implementation of boolean predicates + /// + public override Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ pred, IFunctionalMap/* Var -> Element */ state) { + //Contract.Requires(pred != null); + Contract.Ensures(Contract.Result() != null); + if (pred is IFunApp) { + IFunApp fun = (IFunApp)pred; + if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality + { + IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + if (leftArg is IVariable) { + return Eval(rightArg, state); + } else if (rightArg is IVariable) { + return Eval(leftArg, state); + } + } + } + // otherwise we simply return Top + return IntervalElement.Top; + } + + /// + /// Evaluate the expression (that is assured to be an arithmetic expression, in the state passed as a parameter + /// + private IntervalElement/*!*/ Eval(IExpr/*!*/ exp, IFunctionalMap/* Var -> Element */ state) { + Contract.Requires((exp != null)); + Contract.Ensures(Contract.Result() != null); + + IntervalElement/*!*/ retVal = (IntervalElement/*!*/)cce.NonNull(Top); + + // Eval the expression by structural induction + + + if (exp is IVariable && state != null) // A variable + { + object lookup = state[exp]; + if (lookup is IntervalElement) + retVal = (IntervalElement)lookup; + else { + retVal = (IntervalElement)Top; + } + } else if (exp is IFunApp) { + IFunApp fun = (IFunApp)exp; + + if (fun.FunctionSymbol is IntSymbol) // An integer + { + IntSymbol intSymb = (IntSymbol)fun.FunctionSymbol; + BigNum val = intSymb.Value; + + retVal = IntervalElement.Factory(val); + } else if (fun.FunctionSymbol.Equals(Int.Negate)) // An unary minus + { + IExpr/*!*/ arg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IntervalElement/*!*/ argEval = Eval(arg, state); + Contract.Assert(argEval != null); + IntervalElement/*!*/ zero = IntervalElement.Factory(BigNum.ZERO); + Contract.Assert(zero != null); + + retVal = zero - argEval; + } else if (fun.Arguments.Count == 2) { + IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + + IntervalElement/*!*/ leftVal = Eval(left, state); + Contract.Assert(leftVal != null); + IntervalElement/*!*/ rightVal = Eval(right, state); + Contract.Assert(rightVal != null); + + if (fun.FunctionSymbol.Equals(Int.Add)) + retVal = leftVal + rightVal; + else if (fun.FunctionSymbol.Equals(Int.Sub)) + retVal = leftVal - rightVal; + else if (fun.FunctionSymbol.Equals(Int.Mul)) + retVal = leftVal * rightVal; + else if (fun.FunctionSymbol.Equals(Int.Div)) + retVal = leftVal / rightVal; + else if (fun.FunctionSymbol.Equals(Int.Mod)) + retVal = leftVal % rightVal; + } + } + + return retVal; + } + + /// + /// Inner class standing for an interval on integers, possibly unbounded + /// + private class IntervalElement : Element { + protected static readonly IntervalElement/*!*/ TopInterval = new IntervalElement(new MinusInfinity(), new PlusInfinity()); // Top = [-oo , +oo] + protected static readonly IntervalElement/*!*/ BottomInterval = new IntervalElement(new PlusInfinity(), new MinusInfinity()); // Bottom = [+oo, -oo] + + private readonly ExtendedInt/*!*/ inf; + private readonly ExtendedInt/*!*/ sup; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(inf != null); + Contract.Invariant(sup != null); + } + + public ExtendedInt/*!*/ Inf { + get { + Contract.Ensures(Contract.Result() != null); + + return inf; + } + } + + public ExtendedInt/*!*/ Sup { + get { + Contract.Ensures(Contract.Result() != null); + + return sup; + } + } + + // Construct the inteval [val, val] + protected IntervalElement(BigNum val) { + this.inf = this.sup = ExtendedInt.Factory(val); + // base(); + } + + // Construct the interval [inf, sup] + protected IntervalElement(BigNum infInt, BigNum supInt) { + this.inf = ExtendedInt.Factory(infInt); + this.sup = ExtendedInt.Factory(supInt); + // base(); // to please the compiler... + } + + protected IntervalElement(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + this.inf = inf; + this.sup = sup; + // base(); + } + + // Construct an Interval + public static IntervalElement/*!*/ Factory(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires((sup != null)); + Contract.Requires((inf != null)); + Contract.Ensures(Contract.Result() != null); + if (inf is MinusInfinity && sup is PlusInfinity) + return Top; + if (inf > sup) + return Bottom; + // otherwise... + return new IntervalElement(inf, sup); + } + + public static IntervalElement/*!*/ Factory(BigNum i) { + Contract.Ensures(Contract.Result() != null); + return new IntervalElement(i); + } + + public static IntervalElement/*!*/ Factory(BigNum inf, BigNum sup) { + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ i = ExtendedInt.Factory(inf); + ExtendedInt/*!*/ s = ExtendedInt.Factory(sup); + + return Factory(i, s); + } + + static public IntervalElement/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + + return TopInterval; + } + } + + static public IntervalElement/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + + return BottomInterval; + } + } + + public bool IsTop() { + return this.inf is MinusInfinity && this.sup is PlusInfinity; + } + + public bool IsBottom() { + return this.inf > this.sup; + } + + #region Below are the arithmetic operations lifted to intervals + + // Addition + public static IntervalElement/*!*/ operator +(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ inf = a.inf + b.inf; + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = a.sup + b.sup; + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Subtraction + public static IntervalElement/*!*/ operator -(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ inf = a.inf - b.sup; + Contract.Assert(inf != null); + + ExtendedInt/*!*/ sup = a.sup - b.inf; + Contract.Assert(sup != null); + IntervalElement/*!*/ sub = Factory(inf, sup); + Contract.Assert(sub != null); + + return sub; + } + + // Multiplication + public static IntervalElement/*!*/ operator *(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ infinf = a.inf * b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf * b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup * b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup * b.sup; + Contract.Assert(supsup != null); + + ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Division + public static IntervalElement/*!*/ operator /(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.inf.IsZero && b.sup.IsZero) // Check division by zero + return IntervalElement.Top; + + ExtendedInt/*!*/ infinf = a.inf / b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf / b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup / b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup / b.sup; + Contract.Assert(supsup != null); + + ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Division + public static IntervalElement/*!*/ operator %(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.inf.IsZero && b.sup.IsZero) // Check division by zero + return IntervalElement.Top; + + ExtendedInt/*!*/ infinf = a.inf % b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf % b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup % b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup % b.sup; + Contract.Assert(supsup != null); + + ExtendedInt inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + ExtendedInt sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + + return Factory(inf, sup); + } + + #endregion + + #region Overriden methods + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + // Real copying should not be needed because intervals are immutable? + return this; + /* + int valInf = this.inf.Value; + int valSup = this.sup.Value; + + ExtendedInt clonedInf = ExtendedInt.Factory(valInf); + ExtendedInt clonedSup = ExtendedInt.Factory(valSup); + + return Factory(clonedInf, clonedSup); + */ + } + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "[" + this.inf + ", " + this.sup + "]"; + } + + #endregion + } + } + + + /// The interface for an extended integer + /// + [ContractClass(typeof(ExtendedIntContracts))] + abstract class ExtendedInt { + private static readonly PlusInfinity/*!*/ cachedPlusInf = new PlusInfinity(); + private static readonly MinusInfinity/*!*/ cachedMinusInf = new MinusInfinity(); + + static public ExtendedInt/*!*/ PlusInfinity { + get { + Contract.Ensures(Contract.Result() != null); + + return cachedPlusInf; + } + } + + static public ExtendedInt/*!*/ MinusInfinity { + get { + Contract.Ensures(Contract.Result() != null); + + return cachedMinusInf; + } + } + + public abstract BigNum Value { + get; + } + + public abstract int Signum { + get; + } + + public bool IsZero { + get { + return Signum == 0; + } + } + + public bool IsPositive { + get { + return Signum > 0; + } + } + + public bool IsNegative { + get { + return Signum < 0; + } + } + + + #region Below are the extensions of arithmetic operations on extended integers + + // Addition + public static ExtendedInt/*!*/ operator +(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return b; + } else { + return ExtendedInt.Factory(a.Value + b.Value); + } + } + + // Subtraction + public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return UnaryMinus(b); + } else { + return ExtendedInt.Factory(a.Value - b.Value); + } + } + + // Unary minus + public static ExtendedInt/*!*/ operator -(ExtendedInt/*!*/ a) { + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + // BUGBUG: Some compiler error prevents the unary minus operator from being used + return UnaryMinus(a); + } + + // Unary minus + public static ExtendedInt/*!*/ UnaryMinus(ExtendedInt/*!*/ a) { + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a is PlusInfinity) + return cachedMinusInf; + if (a is MinusInfinity) + return cachedPlusInf; + else // a is a PureInteger + return new PureInteger(-a.Value); + } + + // Multiplication + public static ExtendedInt/*!*/ operator *(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (a.IsZero) { + return a; + } else if (b.IsZero) { + return b; + } else if (a is InfinitaryInt) { + if (b.IsPositive) { + return a; + } else { + return UnaryMinus(a); + } + } else if (b is InfinitaryInt) { + if (a.IsPositive) { + return b; + } else { + return UnaryMinus(b); + } + } else { + return ExtendedInt.Factory(a.Value * b.Value); + } + } + + // Division + public static ExtendedInt/*!*/ operator /(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.IsZero) { + return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; + } + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return b; + } else { + return ExtendedInt.Factory(a.Value / b.Value); + } + } + + // Modulo + public static ExtendedInt/*!*/ operator %(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + if (b.IsZero) { + return a.IsPositive ? (ExtendedInt)cachedPlusInf : cachedMinusInf; + } + if (a is InfinitaryInt) { + return a; + } else if (b is InfinitaryInt) { + return b; + } else { + return ExtendedInt.Factory(a.Value % b.Value); + } + } + + #endregion + + #region Inf and Sup operations + + public abstract int CompareTo(ExtendedInt/*!*/ that); + + public static bool operator <(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) < 0; + } + + public static bool operator >(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) > 0; + } + + public static bool operator <=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) <= 0; + } + + public static bool operator >=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Requires(inf != null && sup != null); + return inf.CompareTo(sup) >= 0; + } + + public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Ensures(Contract.Result() != null); + if (inf < sup) + return inf; + else + return sup; + } + + public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { + Contract.Requires(d != null); + Contract.Requires(c != null); + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ infab = Inf(a, b); + Contract.Assert(infab != null); + ExtendedInt/*!*/ infcd = Inf(c, d); + Contract.Assert(infcd != null); + + return Inf(infab, infcd); + } + + public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Ensures(Contract.Result() != null); + if (inf > sup) + return inf; + else + return sup; + } + + public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { + Contract.Requires(d != null); + Contract.Requires(c != null); + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result() != null); + ExtendedInt/*!*/ supab = Sup(a, b); + Contract.Assert(supab != null); + ExtendedInt/*!*/ supcd = Sup(c, d); + Contract.Assert(supcd != null); + + return Sup(supab, supcd); + } + + #endregion + + // Return the ExtendedInt corresponding to the value + public static ExtendedInt/*!*/ Factory(BigNum val) { + Contract.Ensures(Contract.Result() != null); + return new PureInteger(val); + } + } + [ContractClassFor(typeof(ExtendedInt))] + abstract class ExtendedIntContracts : ExtendedInt { + public override int CompareTo(ExtendedInt that) { + Contract.Requires(that != null); + throw new NotImplementedException(); + } + } + + // Stands for a normal (finite) integer x + class PureInteger : ExtendedInt { + public PureInteger(BigNum i) { + this.val = i; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return this.Value.ToString(); + } + + private BigNum val; + public override BigNum Value { + get { + return this.val; + } + } + + public override int Signum { + get { + return val.Signum; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is PlusInfinity) + return -1; + else if (that is PureInteger) + return this.Value.CompareTo(that.Value); + else // then that is a MinusInfinity + return 1; + } + } + + abstract class InfinitaryInt : ExtendedInt { + public override BigNum Value { + get { + throw new InvalidOperationException(); + } + } + } + + class PlusInfinity : InfinitaryInt { + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "+oo"; + } + + public override int Signum { + get { + return 1; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is PlusInfinity) + return 0; + else + return 1; + } + } + + class MinusInfinity : InfinitaryInt { + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return "-oo"; + } + + public override int Signum { + get { + return -1; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is MinusInfinity) + return 0; + else + return -1; + } + } +} diff --git a/Source/AIFramework/VariableMap/MicroLattice.cs b/Source/AIFramework/VariableMap/MicroLattice.cs index ef98f8f7..f46349b7 100644 --- a/Source/AIFramework/VariableMap/MicroLattice.cs +++ b/Source/AIFramework/VariableMap/MicroLattice.cs @@ -1,105 +1,105 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework -{ - using System.Diagnostics.Contracts; - using System.Collections; - using System.Diagnostics; - //using System.Compiler; - using Microsoft.AbstractInterpretationFramework.Collections; - - /// - /// Interface for a lattice that works on a per-variable basis. - /// - /// - [ContractClass(typeof(MicroLatticeContracts))] - public abstract class MicroLattice : MathematicalLattice - { - /// - /// Returns the predicate on the given variable for the given - /// lattice element. - /// - public abstract IExpr/*!*/ ToPredicate(IVariable/*!*/ v, Element/*!*/ e); - /* requires !e.IsBottom && !e.IsTop; */ - - /// - /// Allows the lattice to specify whether it understands a particular function symbol. - /// - /// The lattice is always allowed to "true" even when it really can't do anything with - /// such functions; however, it is advantageous to say "false" when possible to avoid - /// being called to do certain things. - /// - /// The arguments to a function are provided for context so that the lattice can say - /// true or false for the same function symbol in different situations. For example, - /// a lattice may understand the multiplication of a variable and a constant but not - /// of two variables. The implementation of a lattice should not hold on to the - /// arguments. - /// - /// The function symbol. - /// The argument context. - /// True if it may understand f, false if it does not understand f. - public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); - - /// - /// Set this property to true if the implemented MicroLattice can handle basic arithmetic. - /// Stated otherwise this property is set to true if the MicroLattice provides a transfer function for a predicate in a given state - /// - public virtual bool UnderstandsBasicArithmetics - { - get { return false; } - } - - /// - /// Evaluate the predicate e and a yield the lattice element - /// that is implied by it. - /// - /// The predicate that is assumed to contain 1 variable. - /// The most precise lattice element that is implied by the predicate. - public abstract Element/*!*/ EvaluatePredicate(IExpr/*!*/ e); - - /// - /// Evaluate the predicate e and yield an overapproximation of the predicate under the state that is passed as a parameter - /// Note that unless the subclass implement it, the default behavior is to evaluate the predicate stateless, that implies that it - /// is evaluated in any possible context, i.e. it is an upper approximation - /// - public virtual Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ e, IFunctionalMap state){ -Contract.Requires(e != null); -Contract.Ensures(Contract.Result() != null); - return EvaluatePredicate(e); - } - - /// - /// Give an expression (often a value) that can be used to substitute for - /// the variable. - /// - /// A lattice element. - /// The null value if no such expression can be given. - public abstract IExpr GetFoldExpr(Element/*!*/ e); - } - [ContractClassFor(typeof(MicroLattice))] - public abstract class MicroLatticeContracts : MicroLattice { - public override IExpr ToPredicate(IVariable v, MathematicalLattice.Element e) { - Contract.Requires(v != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - public override bool Understands(IFunctionSymbol f, IList args) { - Contract.Requires(f != null); - Contract.Requires(args != null); - throw new System.NotImplementedException(); - } - public override Element EvaluatePredicate(IExpr e) { - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - throw new System.NotImplementedException(); - } - public override IExpr GetFoldExpr(MathematicalLattice.Element e) { - Contract.Requires(e != null); - throw new System.NotImplementedException(); - } - } +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Diagnostics.Contracts; + using System.Collections; + using System.Diagnostics; + //using System.Compiler; + using Microsoft.AbstractInterpretationFramework.Collections; + + /// + /// Interface for a lattice that works on a per-variable basis. + /// + /// + [ContractClass(typeof(MicroLatticeContracts))] + public abstract class MicroLattice : MathematicalLattice + { + /// + /// Returns the predicate on the given variable for the given + /// lattice element. + /// + public abstract IExpr/*!*/ ToPredicate(IVariable/*!*/ v, Element/*!*/ e); + /* requires !e.IsBottom && !e.IsTop; */ + + /// + /// Allows the lattice to specify whether it understands a particular function symbol. + /// + /// The lattice is always allowed to "true" even when it really can't do anything with + /// such functions; however, it is advantageous to say "false" when possible to avoid + /// being called to do certain things. + /// + /// The arguments to a function are provided for context so that the lattice can say + /// true or false for the same function symbol in different situations. For example, + /// a lattice may understand the multiplication of a variable and a constant but not + /// of two variables. The implementation of a lattice should not hold on to the + /// arguments. + /// + /// The function symbol. + /// The argument context. + /// True if it may understand f, false if it does not understand f. + public abstract bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args); + + /// + /// Set this property to true if the implemented MicroLattice can handle basic arithmetic. + /// Stated otherwise this property is set to true if the MicroLattice provides a transfer function for a predicate in a given state + /// + public virtual bool UnderstandsBasicArithmetics + { + get { return false; } + } + + /// + /// Evaluate the predicate e and a yield the lattice element + /// that is implied by it. + /// + /// The predicate that is assumed to contain 1 variable. + /// The most precise lattice element that is implied by the predicate. + public abstract Element/*!*/ EvaluatePredicate(IExpr/*!*/ e); + + /// + /// Evaluate the predicate e and yield an overapproximation of the predicate under the state that is passed as a parameter + /// Note that unless the subclass implement it, the default behavior is to evaluate the predicate stateless, that implies that it + /// is evaluated in any possible context, i.e. it is an upper approximation + /// + public virtual Element/*!*/ EvaluatePredicateWithState(IExpr/*!*/ e, IFunctionalMap state){ +Contract.Requires(e != null); +Contract.Ensures(Contract.Result() != null); + return EvaluatePredicate(e); + } + + /// + /// Give an expression (often a value) that can be used to substitute for + /// the variable. + /// + /// A lattice element. + /// The null value if no such expression can be given. + public abstract IExpr GetFoldExpr(Element/*!*/ e); + } + [ContractClassFor(typeof(MicroLattice))] + public abstract class MicroLatticeContracts : MicroLattice { + public override IExpr ToPredicate(IVariable v, MathematicalLattice.Element e) { + Contract.Requires(v != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + public override bool Understands(IFunctionSymbol f, IList args) { + Contract.Requires(f != null); + Contract.Requires(args != null); + throw new System.NotImplementedException(); + } + public override Element EvaluatePredicate(IExpr e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + throw new System.NotImplementedException(); + } + public override IExpr GetFoldExpr(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new System.NotImplementedException(); + } + } } \ No newline at end of file diff --git a/Source/AIFramework/VariableMap/Nullness.cs b/Source/AIFramework/VariableMap/Nullness.cs index 613f55e0..474792e0 100644 --- a/Source/AIFramework/VariableMap/Nullness.cs +++ b/Source/AIFramework/VariableMap/Nullness.cs @@ -1,260 +1,260 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Diagnostics.Contracts; -namespace Microsoft.AbstractInterpretationFramework { - using System.Collections; - using System.Diagnostics; - //using System.Compiler.Analysis; - - public class NullnessLattice : MicroLattice { - readonly INullnessFactory/*!*/ factory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(factory != null); - } - - - public NullnessLattice(INullnessFactory/*!*/ factory) { - Contract.Requires(factory != null); - this.factory = factory; - // base(); - } - - enum Value { - Bottom, - NotNull, - Null, - MayBeNull - } - - private class Elt : Element { - public Value value; - - public Elt(Value v) { - this.value = v; - } - - [Pure] - public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new Elt(this.value); - } - } - - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.MayBeNull); - } - } - - public override Element/*!*/ Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Bottom); - } - } - - public static Element/*!*/ Null { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.Null); - } - } - - public static Element/*!*/ NotNull { - get { - Contract.Ensures(Contract.Result() != null); - return new Elt(Value.NotNull); - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.value == Value.MayBeNull; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return e.value == Value.Bottom; - } - - public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return (a.value == b.value) ? a : (Elt)Top; - } - - public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return (a.value == b.value) ? a : (Elt)Bottom; - } - - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - return Join(first, second); - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that - { - //Contract.Requires(first != null); - //Contract.Requires(second != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - return a.value == b.value; - } - - public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { - //Contract.Requires(element != null); - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - if (e.value == Value.NotNull) { - return factory.Neq(var, factory.Null); - } - if (e.value == Value.Null) { - return factory.Eq(var, factory.Null); - } - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - throw new System.Exception(); - } - - public override IExpr GetFoldExpr(Element/*!*/ e) { - //Contract.Requires(e != null); - Elt elt = (Elt)e; - if (elt.value == Value.Null) { - return factory.Null; - } else { - // can't fold into an expression - return null; - } - } - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) || - f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { - - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for "x OP null" or "null OP x" where OP is "==" or "!=". - if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { - return true; - } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { - return true; - } - } - return false; - } - - public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { - //Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - IFunApp nary = e as IFunApp; - if (nary != null) { - bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); - if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { - IList/**//*!*/ args = nary.Arguments; - Contract.Assert(args != null); - Contract.Assert(args.Count == 2); - IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); - IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); - - // Look for "x OP null" or "null OP x" where OP is "==" or "!=". - IVariable var = null; - if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { - var = (IVariable)arg0; - } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { - var = (IVariable)arg1; - } - - if (var != null) // found the pattern - { - return isEq ? Null : NotNull; - } - } - } - return Top; - } - } - -#if false - - public class NullnessMicroLattice : MicroLattice - { - public override MicroLatticeElement Top { get { return NullnessLatticeElement.Top; } } - public override MicroLatticeElement Bottom { get { return NullnessLatticeElement.Bottom; } } - - - public override MicroLatticeElement EvaluateExpression (Expr e, LookupValue lookup) - { - if (e is LiteralExpr && ((LiteralExpr)e).Val == null) - { - return NullnessLatticeElement.Null; - } - return Top; - } - - - public override MicroLatticeElement EvaluatePredicate (Expr e, LookupValue lookup) - { - NAryExpr nary = e as NAryExpr; - if (nary != null && - (nary.Fun.FunctionName.Equals("==") || nary.Fun.FunctionName.Equals("!="))) - { - Debug.Assert(nary.Args.Length == 2); - - Expr arg0 = nary.Args[0], arg1 = nary.Args[1]; - Variable var = null; - - // Look for "x OP null" or "null OP x" where OP is "==" or "!=". - if (arg0 is IdentifierExpr && arg1 is LiteralExpr && ((LiteralExpr)arg1).Val == null) - { - var = ((IdentifierExpr)arg0).Decl; - } - else if (arg1 is IdentifierExpr && arg0 is LiteralExpr && ((LiteralExpr)arg0).Val == null) - { - var = ((IdentifierExpr)arg1).Decl; - } - - if (var != null) // found the pattern - { - return nary.Fun.FunctionName.Equals("==") ? - NullnessLatticeElement.Null : - NullnessLatticeElement.NotNull; - } - } - return Top; - } - } - -#endif - -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + + public class NullnessLattice : MicroLattice { + readonly INullnessFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public NullnessLattice(INullnessFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + enum Value { + Bottom, + NotNull, + Null, + MayBeNull + } + + private class Elt : Element { + public Value value; + + public Elt(Value v) { + this.value = v; + } + + [Pure] + public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new Elt(this.value); + } + } + + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.MayBeNull); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Bottom); + } + } + + public static Element/*!*/ Null { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.Null); + } + } + + public static Element/*!*/ NotNull { + get { + Contract.Ensures(Contract.Result() != null); + return new Elt(Value.NotNull); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.value == Value.MayBeNull; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.value == Value.Bottom; + } + + public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return (a.value == b.value) ? a : (Elt)Top; + } + + public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return (a.value == b.value) ? a : (Elt)Bottom; + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return a.value == b.value; + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + if (e.value == Value.NotNull) { + return factory.Neq(var, factory.Null); + } + if (e.value == Value.Null) { + return factory.Eq(var, factory.Null); + } + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + throw new System.Exception(); + } + + public override IExpr GetFoldExpr(Element/*!*/ e) { + //Contract.Requires(e != null); + Elt elt = (Elt)e; + if (elt.value == Value.Null) { + return factory.Null; + } else { + // can't fold into an expression + return null; + } + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) || + f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { + + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for "x OP null" or "null OP x" where OP is "==" or "!=". + if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { + return true; + } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { + return true; + } + } + return false; + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + IFunApp nary = e as IFunApp; + if (nary != null) { + bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { + IList/**//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); + + // Look for "x OP null" or "null OP x" where OP is "==" or "!=". + IVariable var = null; + if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { + var = (IVariable)arg0; + } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { + var = (IVariable)arg1; + } + + if (var != null) // found the pattern + { + return isEq ? Null : NotNull; + } + } + } + return Top; + } + } + +#if false + + public class NullnessMicroLattice : MicroLattice + { + public override MicroLatticeElement Top { get { return NullnessLatticeElement.Top; } } + public override MicroLatticeElement Bottom { get { return NullnessLatticeElement.Bottom; } } + + + public override MicroLatticeElement EvaluateExpression (Expr e, LookupValue lookup) + { + if (e is LiteralExpr && ((LiteralExpr)e).Val == null) + { + return NullnessLatticeElement.Null; + } + return Top; + } + + + public override MicroLatticeElement EvaluatePredicate (Expr e, LookupValue lookup) + { + NAryExpr nary = e as NAryExpr; + if (nary != null && + (nary.Fun.FunctionName.Equals("==") || nary.Fun.FunctionName.Equals("!="))) + { + Debug.Assert(nary.Args.Length == 2); + + Expr arg0 = nary.Args[0], arg1 = nary.Args[1]; + Variable var = null; + + // Look for "x OP null" or "null OP x" where OP is "==" or "!=". + if (arg0 is IdentifierExpr && arg1 is LiteralExpr && ((LiteralExpr)arg1).Val == null) + { + var = ((IdentifierExpr)arg0).Decl; + } + else if (arg1 is IdentifierExpr && arg0 is LiteralExpr && ((LiteralExpr)arg0).Val == null) + { + var = ((IdentifierExpr)arg1).Decl; + } + + if (var != null) // found the pattern + { + return nary.Fun.FunctionName.Equals("==") ? + NullnessLatticeElement.Null : + NullnessLatticeElement.NotNull; + } + } + return Top; + } + } + +#endif + +} diff --git a/Source/AIFramework/VariableMap/VariableMapLattice.cs b/Source/AIFramework/VariableMap/VariableMapLattice.cs index 172cef01..752d3f01 100644 --- a/Source/AIFramework/VariableMap/VariableMapLattice.cs +++ b/Source/AIFramework/VariableMap/VariableMapLattice.cs @@ -1,854 +1,854 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.AbstractInterpretationFramework { - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - - using Microsoft.AbstractInterpretationFramework; - using Microsoft.AbstractInterpretationFramework.Collections; - - using Microsoft.Boogie; - - using IMutableSet = Microsoft.Boogie.GSet; - using ISet = Microsoft.Boogie.GSet; - using Set = Microsoft.Boogie.GSet; - using HashSet = Microsoft.Boogie.GSet; - - /// - /// Creates a lattice that works for several variables given a MicroLattice. Assumes - /// if one variable is bottom, then all variables are bottom. - /// - public class VariableMapLattice : Lattice { - private class Elt : Element { - /// - /// IsBottom(e) iff e.constraints == null - /// - /*MayBeNull*/ - private IFunctionalMap constraints; // of type IVariable -> LATTICE_ELEMENT - public IFunctionalMap Constraints { - get { - return this.constraints; - } - } - - private Elt(bool top) { - if (top) { - this.constraints = FunctionalHashtable.Empty; - } else { - this.constraints = null; - } - } - - public override Element/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new Elt(this.constraints); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - if (constraints == null) { - return ""; - } - string s = "["; - string sep = ""; - foreach (IVariable/*!*/ v in cce.NonNull(constraints.Keys)) { - Contract.Assert(v != null); - Element m = (Element)constraints[v]; - s += sep + v.Name + " -> " + m; - sep = ", "; - } - return s + "]"; - } - - public static readonly Elt/*!*/ Top = new Elt(true); - public static readonly Elt/*!*/ Bottom = new Elt(false); - - - public Elt(IFunctionalMap constraints) { - this.constraints = constraints; - } - - public bool IsBottom { - get { - return this.constraints == null; - } - } - - public int Count { - get { - return this.constraints == null ? 0 : this.constraints.Count; - } - } - - public IEnumerable/**//*!*/ Variables { - get { - Contract.Requires(!this.IsBottom); - Contract.Ensures(Contract.Result() != null); - Contract.Assume(this.constraints != null); - return cce.NonNull(this.constraints.Keys); - } - } - - public IEnumerable/**//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) { - Contract.Ensures(Contract.Result() != null); - if (variableComparer == null) { - return Variables; - } else { - ArrayList /*IVariable*/ vars = new ArrayList /*IVariable*/ (Count); - foreach (IVariable variable in Variables) { - vars.Add(variable); - } - vars.Sort(variableComparer); - return vars; - } - } - - public Element Lookup(IVariable v) { - if ((v == null) || (this.constraints == null)) { - return null; - } - return (Element)this.constraints[v]; - } - - public Element this[IVariable/*!*/ key] { - get { - Contract.Requires(!this.IsBottom); - Contract.Requires(key != null); - Contract.Assume(this.constraints != null); - return (Element)constraints[key]; - } - } - - /// - /// Add a new entry in the functional map: var --> value. - /// If the variable is already there, throws an exception - /// - public Elt/*!*/ Add(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { - Contract.Requires(microLattice != null); - Contract.Requires(value != null); - Contract.Requires(var != null); - Contract.Requires((!this.IsBottom)); - Contract.Ensures(Contract.Result() != null); - Contract.Assume(this.constraints != null); - Contract.Assert(!this.constraints.Contains(var)); - - if (microLattice.IsBottom(value)) { - return Bottom; - } - if (microLattice.IsTop(value)) { - return this.Remove(var, microLattice); - } - - return new Elt(this.constraints.Add(var, value)); - } - - /// - /// Set the value of the variable in the functional map - /// If the variable is not already there, throws an exception - /// - public Elt/*!*/ Set(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { - Contract.Requires(microLattice != null); - Contract.Requires(value != null); - Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - if (microLattice.IsBottom(value)) { - return Bottom; - } - if (microLattice.IsTop(value)) { - return this.Remove(var, microLattice); - } - - Contract.Assume(this.constraints != null); - Contract.Assert(this.constraints.Contains(var)); - - // this.constraints[var] = value; - IFunctionalMap newMap = this.constraints.Set(var, value); - - return new Elt(newMap); - } - - public Elt/*!*/ Remove(IVariable/*!*/ var, MicroLattice microLattice) { - Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - if (this.IsBottom) { - return this; - } - Contract.Assume(this.constraints != null); - return new Elt(this.constraints.Remove(var)); - } - - public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice) { - Contract.Requires(microLattice != null); - Contract.Requires(newName != null); - Contract.Requires(oldName != null); - Contract.Requires((!this.IsBottom)); - Contract.Ensures(Contract.Result() != null); - Element value = this[oldName]; - if (value == null) { - return this; - } // 'oldName' isn't in the map, so neither will be 'newName' - Contract.Assume(this.constraints != null); - IFunctionalMap newMap = this.constraints.Remove(oldName); - newMap = newMap.Add(newName, value); - return new Elt(newMap); - } - - [Pure] - public override ICollection/*!*/ FreeVariables() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - throw new System.NotImplementedException(); - } - - } // class - - private readonly MicroLattice/*!*/ microLattice; - - private readonly IPropExprFactory/*!*/ propExprFactory; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(microLattice != null); - Contract.Invariant(propExprFactory != null); - } - - - private readonly /*maybe null*/IComparer variableComparer; - - public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer) - : base(valueExprFactory) { - Contract.Requires(microLattice != null); - Contract.Requires(valueExprFactory != null); - Contract.Requires(propExprFactory != null); - this.propExprFactory = propExprFactory; - this.microLattice = microLattice; - this.variableComparer = variableComparer; - // base(valueExprFactory); - } - - protected override object/*!*/ UniqueId { - get { - Contract.Ensures(Contract.Result() != null); - return this.microLattice.GetType(); - } - } - - public override Element/*!*/ Top { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Top; - } - } - - public override Element Bottom { - get { - Contract.Ensures(Contract.Result() != null); - return Elt.Bottom; - } - } - - public override bool IsTop(Element/*!*/ element) { - //Contract.Requires(element != null); - Elt e = (Elt)element; - return !e.IsBottom && e.Count == 0; - } - - public override bool IsBottom(Element/*!*/ element) { - //Contract.Requires(element != null); - return ((Elt)element).IsBottom; - } - - protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - // return true iff every constraint in "this" is no weaker than the corresponding - // constraint in "that" and there are no additional constraints in "that" - foreach (IVariable/*!*/ var in a.Variables) { - Contract.Assert(var != null); - Element thisValue = cce.NonNull(a[var]); - - Element thatValue = b[var]; - if (thatValue == null) { - continue; - } // it's okay for "a" to know something "b" doesn't - - if (this.microLattice.LowerThan(thisValue, thatValue)) { - continue; - } // constraint for "var" satisfies AtMost relation - - return false; - } - foreach (IVariable/*!*/ var in b.Variables) { - Contract.Assert(var != null); - if (a.Lookup(var) != null) { - continue; - } // we checked this case in the loop above - - Element thatValue = cce.NonNull(b[var]); - if (this.microLattice.IsTop(thatValue)) { - continue; - } // this is a trivial constraint - - return false; - } - return true; - } - - private Elt/*!*/ AddConstraint(Element/*!*/ element, IVariable/*!*/ var, /*MicroLattice*/Element/*!*/ newValue) { - Contract.Requires((newValue != null)); - Contract.Requires((var != null)); - Contract.Requires((element != null)); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - if (!e.IsBottom && !this.microLattice.IsBottom(newValue)) // if we're not at bottom - { - /*MicroLattice*/ - Element currentValue = e[var]; - - if (currentValue == null) { - // No information currently, so we just add the new info. - return e.Add(var, newValue, this.microLattice); - } else { - // Otherwise, take the meet of the new and current info. - //return e.Add(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); - return e.Set(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); - } - } - return e; - } - - public override string/*!*/ ToString(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - Elt e = (Elt)element; - - if (IsTop(e)) { - return ""; - } - if (IsBottom(e)) { - return ""; - } - - int k = 0; - System.Text.StringBuilder buffer = new System.Text.StringBuilder(); - foreach (IVariable/*!*/ key in e.SortedVariables(variableComparer)) { - Contract.Assert(key != null); - if (k++ > 0) { - buffer.Append("; "); - } - buffer.AppendFormat("{0} = {1}", key, e[key]); - } - return buffer.ToString(); - } - - public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - IFunctionalMap newMap = FunctionalHashtable.Empty; - foreach (IVariable/*!*/ key in a.Variables) { - Contract.Assert(key != null); - Element aValue = a[key]; - Element bValue = b[key]; - - if (aValue != null && bValue != null) { - // Keep only the variables known to both elements. - Element newValue = this.microLattice.Join(aValue, bValue); - newMap = newMap.Add(key, newValue); - } - } - Elt/*!*/ join = new Elt(newMap); - Contract.Assert(join != null); - - // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join)); - - return join; - } - - public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires(second != null); - //Contract.Requires(first != null); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - IFunctionalMap newMap = FunctionalHashtable.Empty; - foreach (IVariable/*!*/ key in a.Variables) { - Contract.Assert(key != null); - Element/*!*/ aValue = cce.NonNull(a[key]); - Element bValue = b[key]; - - Element newValue = - bValue == null ? aValue : - this.microLattice.Meet(aValue, bValue); - - newMap = newMap.Add(key, newValue); - } - foreach (IVariable/*!*/ key in b.Variables) { - Contract.Assert(key != null); - Element aValue = a[key]; - Element bValue = b[key]; - Debug.Assert(bValue != null); - - if (aValue == null) { - // It's a variable we didn't cover in the last loop. - newMap = newMap.Add(key, bValue); - } - } - return new Elt(newMap); - } - - /// - /// Perform the pointwise widening of the elements in the map - /// - public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { - //Contract.Requires((second != null)); - //Contract.Requires((first != null)); - Contract.Ensures(Contract.Result() != null); - Elt a = (Elt)first; - Elt b = (Elt)second; - - // Note we have to add those cases as we do not have a "NonTrivialWiden" method - if (a.IsBottom) - return new Elt(b.Constraints); - if (b.IsBottom) - return new Elt(a.Constraints); - - IFunctionalMap newMap = FunctionalHashtable.Empty; - foreach (IVariable/*!*/ key in a.Variables) { - Contract.Assert(key != null); - Element aValue = a[key]; - Element bValue = b[key]; - - if (aValue != null && bValue != null) { - // Keep only the variables known to both elements. - Element newValue = this.microLattice.Widen(aValue, bValue); - newMap = newMap.Add(key, newValue); - } - } - Element/*!*/ widen = new Elt(newMap); - Contract.Assert(widen != null); - // System.Console.WriteLine("{0} widen {1} = {2} ", this.ToString(a), ToString(b), ToString(widen)); - - return widen; - } - - internal static ISet/**//*!*/ VariablesInExpression(IExpr/*!*/ e, ISet/**//*!*/ ignoreVars) { - Contract.Requires(ignoreVars != null); - Contract.Requires(e != null); - Contract.Ensures(Contract.Result() != null); - HashSet s = new HashSet(); - - IFunApp f = e as IFunApp; - IFunction lambda = e as IFunction; - - if (e is IVariable) { - if (!ignoreVars.Contains(e)) - s.Add(e); - } else if (f != null) // e is IFunApp - { - foreach (IExpr/*!*/ arg in f.Arguments) { - Contract.Assert(arg != null); - s.AddAll(VariablesInExpression(arg, ignoreVars)); - } - } else if (lambda != null) { - IMutableSet x = new HashSet(1); - x.Add(lambda.Param); - - // Ignore the bound variable - s.AddAll(VariablesInExpression(lambda.Body, cce.NonNull(Set.Union(ignoreVars, x)))); - } else if (e is IUnknown) { - // skip (actually, it would be appropriate to return the universal set of all variables) - } else { - Debug.Assert(false, "case not handled: " + e); - } - return s; - } - - - private static ArrayList/**//*!*/ FindConjuncts(IExpr e) { - Contract.Ensures(Contract.Result() != null); - ArrayList result = new ArrayList(); - - IFunApp f = e as IFunApp; - if (f != null) { - if (f.FunctionSymbol.Equals(Prop.And)) { - foreach (IExpr arg in f.Arguments) { - result.AddRange(FindConjuncts(arg)); - } - } else if (f.FunctionSymbol.Equals(Prop.Or) - || f.FunctionSymbol.Equals(Prop.Implies)) { - // Do nothing. - } else { - result.Add(e); - } - } else { - result.Add(e); - } - - return result; - } - - private static bool IsSimpleEquality(IExpr expr, out IVariable left, out IVariable right) { - Contract.Ensures(!Contract.Result() || Contract.ValueAtReturn(out left) != null && Contract.ValueAtReturn(out right) != null); - left = null; - right = null; - - // See if we have an equality - IFunApp nary = expr as IFunApp; - if (nary == null || !nary.FunctionSymbol.Equals(Value.Eq)) { - return false; - } - - // See if it is an equality of two variables - IVariable idLeft = nary.Arguments[0] as IVariable; - IVariable idRight = nary.Arguments[1] as IVariable; - if (idLeft == null || idRight == null) { - return false; - } - - left = idLeft; - right = idRight; - return true; - } - - /// - /// Returns true iff the expression is in the form var == arithmeticExpr - /// - private static bool IsArithmeticExpr(IExpr/*!*/ expr) { - Contract.Requires(expr != null); - // System.Console.WriteLine("\t\tIsArithmetic called with {0} of type {1}", expr, expr.GetType().ToString()); - - if (expr is IVariable) // expr is a variable - return true; - else if (expr is IFunApp) // may be ==, +, -, /, % or an integer - { - IFunApp fun = (IFunApp)expr; - - if (fun.FunctionSymbol is IntSymbol) // it is an integer - return true; - else if (fun.FunctionSymbol.Equals(Int.Negate)) // it is an unary minus - return IsArithmeticExpr((IExpr/*!*/)cce.NonNull(fun.Arguments[0])); - else if (fun.Arguments.Count != 2) // A function of two or more operands is not arithmetic - return false; - else { - IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - - if (!(left is IVariable || right is IVariable)) // At least one of the two operands must be a variable - return false; - - if (fun.FunctionSymbol.Equals(Value.Eq) - || fun.FunctionSymbol.Equals(Int.Add) - || fun.FunctionSymbol.Equals(Int.Sub) - || fun.FunctionSymbol.Equals(Int.Mul) - || fun.FunctionSymbol.Equals(Int.Div) - || fun.FunctionSymbol.Equals(Int.Mod)) - return IsArithmeticExpr(left) && IsArithmeticExpr(right); - else - return false; - } - } else { - return false; - } - } - - public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - if (IsTop(element)) { - return propExprFactory.True; - } - if (IsBottom(element)) { - return propExprFactory.False; - } - - Elt e = (Elt)element; - IExpr truth = propExprFactory.True; - IExpr result = truth; - - foreach (IVariable/*!*/ variable in e.SortedVariables(variableComparer)) { - Contract.Assert(variable != null); - Element value = (Element)e[variable]; - - if (value == null || this.microLattice.IsTop(value)) { - continue; - } // Skip variables about which we know nothing. - if (this.microLattice.IsBottom(value)) { - return propExprFactory.False; - } - - IExpr conjunct = this.microLattice.ToPredicate(variable, value); - - result = (result == truth) ? (IExpr)conjunct : (IExpr)propExprFactory.And(result, conjunct); - } - return result; - } - - - public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { - //Contract.Requires(variable != null); - //Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull((Elt)element).Remove(variable, this.microLattice); - } - - private delegate IExpr/*!*/ OnUnableToInline(IVariable/*!*/ var); - private IExpr/*!*/ IdentityVarToExpr(IVariable/*!*/ var) { - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - return var; - } - - /// - /// Return a new expression in which each variable has been - /// replaced by an expression representing what is known about - /// that variable. - /// - private IExpr/*!*/ InlineVariables(Elt/*!*/ element, IExpr/*!*/ expr, ISet/**//*!*/ notInlineable, - OnUnableToInline/*!*/ unableToInline) { - Contract.Requires(unableToInline != null); - Contract.Requires(notInlineable != null); - Contract.Requires(expr != null); - Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); - IVariable var = expr as IVariable; - if (var != null) { - /*MicroLattice*/ - Element value = element[var]; - if (notInlineable.Contains(var) || value == null || this.microLattice.IsTop(value)) { - return unableToInline(var); // We don't know anything about this variable. - } else { - // GetFoldExpr returns null when it can yield an expression that - // can be substituted for the variable. - IExpr valueExpr = this.microLattice.GetFoldExpr(value); - return (valueExpr == null) ? var : valueExpr; - } - } - - // else - - IFunApp fun = expr as IFunApp; - if (fun != null) { - IList newargs = new ArrayList(); - foreach (IExpr/*!*/ arg in fun.Arguments) { - Contract.Assert(arg != null); - newargs.Add(InlineVariables(element, arg, notInlineable, unableToInline)); - } - return fun.CloneWithArguments(newargs); - } - - // else - - IFunction lambda = expr as IFunction; - if (lambda != null) { - IMutableSet x = new HashSet(1); - x.Add(lambda.Param); - - // Don't inline the bound variable - return lambda.CloneWithBody( - InlineVariables(element, lambda.Body, - cce.NonNull(Set.Union(notInlineable, x)), unableToInline) - ); - } - - // else - - if (expr is IUnknown) { - return expr; - } else { - throw - new System.NotImplementedException("cannot inline identifies in expression " + expr); - } - } - - - public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { - //Contract.Requires(expr != null); - //Contract.Requires(element != null); - //Contract.Ensures(Contract.Result() != null); - Elt/*!*/ result = (Elt)element; - Contract.Assert(result != null); - - if (IsBottom(element)) { - return result; // == element - } - - expr = InlineVariables(result, expr, cce.NonNull(Set.Empty), new OnUnableToInline(IdentityVarToExpr)); - - foreach (IExpr/*!*/ conjunct in FindConjuncts(expr)) { - Contract.Assert(conjunct != null); - IVariable left, right; - - if (IsSimpleEquality(conjunct, out left, out right)) { - #region The conjunct is a simple equality - - - Contract.Assert(left != null && right != null); - - Element leftValue = result[left], rightValue = result[right]; - if (leftValue == null) { - leftValue = this.microLattice.Top; - } - if (rightValue == null) { - rightValue = this.microLattice.Top; - } - Element newValue = this.microLattice.Meet(leftValue, rightValue); - result = AddConstraint(result, left, newValue); - result = AddConstraint(result, right, newValue); - - #endregion - } else { - ISet/**/ variablesInvolved = VariablesInExpression(conjunct, Set.Empty); - - if (variablesInvolved.Count == 1) { - #region We have just one variable - - IVariable var = null; - foreach (IVariable/*!*/ v in variablesInvolved) { - Contract.Assert(v != null); - var = v; - } // why is there no better way to get the elements? - Contract.Assert(var != null); - Element/*!*/ value = this.microLattice.EvaluatePredicate(conjunct); - result = AddConstraint(result, var, value); - - #endregion - } else if (IsArithmeticExpr(conjunct) && this.microLattice.UnderstandsBasicArithmetics) { - #region We evalaute an arithmetic expression - - IFunApp fun = (IFunApp)conjunct; - if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality - { - // get the variable to be assigned - IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); - IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); - IExpr/*!*/ var = (leftArg is IVariable) ? leftArg : rightArg; - - Element/*!*/ value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints); - Contract.Assert(value != null); - result = AddConstraint(result, (IVariable/*!*/)cce.NonNull(var), value); - } - #endregion - } - } - } - return result; - } - - - public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { - //Contract.Requires(newName != null); - //Contract.Requires(oldName != null); - //Contract.Requires(element != null); - //Contract.Ensures(Contract.Result() != null); - if (IsBottom(element)) { - return element; - } else { - return ((Elt)element).Rename(oldName, newName, this.microLattice); - } - } - - - public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { - //Contract.Requires(args != null); - //Contract.Requires(f != null); - return f.Equals(Prop.And) || - f.Equals(Value.Eq) || - microLattice.Understands(f, args); - } - - private sealed class EquivalentExprException : CheckedException { - } - private sealed class EquivalentExprInlineCallback { - private readonly IVariable/*!*/ var; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(var != null); - } - - public EquivalentExprInlineCallback(IVariable/*!*/ var) { - Contract.Requires(var != null); - this.var = var; - // base(); - } - - public IExpr/*!*/ ThrowOnUnableToInline(IVariable/*!*/ othervar) - //throws EquivalentExprException; - { - Contract.Requires(othervar != null); - Contract.Ensures(Contract.Result() != null); - Contract.EnsuresOnThrow(true); - if (othervar.Equals(var)) - throw new EquivalentExprException(); - else - return othervar; - } - } - - public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { - //Contract.Requires(prohibitedVars != null); - //Contract.Requires(var != null); - //Contract.Requires(expr != null); - //Contract.Requires(q != null); - //Contract.Requires(e != null); - try { - EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var); - return InlineVariables((Elt)e, expr, cce.NonNull(Set.Empty), - new OnUnableToInline(closure.ThrowOnUnableToInline)); - } catch (EquivalentExprException) { - return null; - } - } - - - /// - /// Check to see if the given predicate holds in the given lattice element. - /// - /// TODO: We leave this unimplemented for now and just return maybe. - /// - /// The lattice element. - /// The predicate. - /// Yes, No, or Maybe - public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { - //Contract.Requires(pred != null); - //Contract.Requires(e != null); - return Answer.Maybe; - } - - /// - /// Answers a disequality about two variables. The same information could be obtained - /// by asking CheckPredicate, but a different implementation may be simpler and more - /// efficient. - /// - /// TODO: We leave this unimplemented for now and just return maybe. - /// - /// The lattice element. - /// The first variable. - /// The second variable. - /// Yes, No, or Maybe. - public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { - //Contract.Requires(var2 != null); - //Contract.Requires(var1 != null); - //Contract.Requires(e != null); - return Answer.Maybe; - } - - public override void Validate() { - base.Validate(); - microLattice.Validate(); - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + + using Microsoft.AbstractInterpretationFramework; + using Microsoft.AbstractInterpretationFramework.Collections; + + using Microsoft.Boogie; + + using IMutableSet = Microsoft.Boogie.GSet; + using ISet = Microsoft.Boogie.GSet; + using Set = Microsoft.Boogie.GSet; + using HashSet = Microsoft.Boogie.GSet; + + /// + /// Creates a lattice that works for several variables given a MicroLattice. Assumes + /// if one variable is bottom, then all variables are bottom. + /// + public class VariableMapLattice : Lattice { + private class Elt : Element { + /// + /// IsBottom(e) iff e.constraints == null + /// + /*MayBeNull*/ + private IFunctionalMap constraints; // of type IVariable -> LATTICE_ELEMENT + public IFunctionalMap Constraints { + get { + return this.constraints; + } + } + + private Elt(bool top) { + if (top) { + this.constraints = FunctionalHashtable.Empty; + } else { + this.constraints = null; + } + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new Elt(this.constraints); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + if (constraints == null) { + return ""; + } + string s = "["; + string sep = ""; + foreach (IVariable/*!*/ v in cce.NonNull(constraints.Keys)) { + Contract.Assert(v != null); + Element m = (Element)constraints[v]; + s += sep + v.Name + " -> " + m; + sep = ", "; + } + return s + "]"; + } + + public static readonly Elt/*!*/ Top = new Elt(true); + public static readonly Elt/*!*/ Bottom = new Elt(false); + + + public Elt(IFunctionalMap constraints) { + this.constraints = constraints; + } + + public bool IsBottom { + get { + return this.constraints == null; + } + } + + public int Count { + get { + return this.constraints == null ? 0 : this.constraints.Count; + } + } + + public IEnumerable/**//*!*/ Variables { + get { + Contract.Requires(!this.IsBottom); + Contract.Ensures(Contract.Result() != null); + Contract.Assume(this.constraints != null); + return cce.NonNull(this.constraints.Keys); + } + } + + public IEnumerable/**//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) { + Contract.Ensures(Contract.Result() != null); + if (variableComparer == null) { + return Variables; + } else { + ArrayList /*IVariable*/ vars = new ArrayList /*IVariable*/ (Count); + foreach (IVariable variable in Variables) { + vars.Add(variable); + } + vars.Sort(variableComparer); + return vars; + } + } + + public Element Lookup(IVariable v) { + if ((v == null) || (this.constraints == null)) { + return null; + } + return (Element)this.constraints[v]; + } + + public Element this[IVariable/*!*/ key] { + get { + Contract.Requires(!this.IsBottom); + Contract.Requires(key != null); + Contract.Assume(this.constraints != null); + return (Element)constraints[key]; + } + } + + /// + /// Add a new entry in the functional map: var --> value. + /// If the variable is already there, throws an exception + /// + public Elt/*!*/ Add(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(value != null); + Contract.Requires(var != null); + Contract.Requires((!this.IsBottom)); + Contract.Ensures(Contract.Result() != null); + Contract.Assume(this.constraints != null); + Contract.Assert(!this.constraints.Contains(var)); + + if (microLattice.IsBottom(value)) { + return Bottom; + } + if (microLattice.IsTop(value)) { + return this.Remove(var, microLattice); + } + + return new Elt(this.constraints.Add(var, value)); + } + + /// + /// Set the value of the variable in the functional map + /// If the variable is not already there, throws an exception + /// + public Elt/*!*/ Set(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(value != null); + Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + if (microLattice.IsBottom(value)) { + return Bottom; + } + if (microLattice.IsTop(value)) { + return this.Remove(var, microLattice); + } + + Contract.Assume(this.constraints != null); + Contract.Assert(this.constraints.Contains(var)); + + // this.constraints[var] = value; + IFunctionalMap newMap = this.constraints.Set(var, value); + + return new Elt(newMap); + } + + public Elt/*!*/ Remove(IVariable/*!*/ var, MicroLattice microLattice) { + Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + if (this.IsBottom) { + return this; + } + Contract.Assume(this.constraints != null); + return new Elt(this.constraints.Remove(var)); + } + + public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + Contract.Requires((!this.IsBottom)); + Contract.Ensures(Contract.Result() != null); + Element value = this[oldName]; + if (value == null) { + return this; + } // 'oldName' isn't in the map, so neither will be 'newName' + Contract.Assume(this.constraints != null); + IFunctionalMap newMap = this.constraints.Remove(oldName); + newMap = newMap.Add(newName, value); + return new Elt(newMap); + } + + [Pure] + public override ICollection/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + throw new System.NotImplementedException(); + } + + } // class + + private readonly MicroLattice/*!*/ microLattice; + + private readonly IPropExprFactory/*!*/ propExprFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(microLattice != null); + Contract.Invariant(propExprFactory != null); + } + + + private readonly /*maybe null*/IComparer variableComparer; + + public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer) + : base(valueExprFactory) { + Contract.Requires(microLattice != null); + Contract.Requires(valueExprFactory != null); + Contract.Requires(propExprFactory != null); + this.propExprFactory = propExprFactory; + this.microLattice = microLattice; + this.variableComparer = variableComparer; + // base(valueExprFactory); + } + + protected override object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result() != null); + return this.microLattice.GetType(); + } + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Top; + } + } + + public override Element Bottom { + get { + Contract.Ensures(Contract.Result() != null); + return Elt.Bottom; + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return !e.IsBottom && e.Count == 0; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + return ((Elt)element).IsBottom; + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + // return true iff every constraint in "this" is no weaker than the corresponding + // constraint in "that" and there are no additional constraints in "that" + foreach (IVariable/*!*/ var in a.Variables) { + Contract.Assert(var != null); + Element thisValue = cce.NonNull(a[var]); + + Element thatValue = b[var]; + if (thatValue == null) { + continue; + } // it's okay for "a" to know something "b" doesn't + + if (this.microLattice.LowerThan(thisValue, thatValue)) { + continue; + } // constraint for "var" satisfies AtMost relation + + return false; + } + foreach (IVariable/*!*/ var in b.Variables) { + Contract.Assert(var != null); + if (a.Lookup(var) != null) { + continue; + } // we checked this case in the loop above + + Element thatValue = cce.NonNull(b[var]); + if (this.microLattice.IsTop(thatValue)) { + continue; + } // this is a trivial constraint + + return false; + } + return true; + } + + private Elt/*!*/ AddConstraint(Element/*!*/ element, IVariable/*!*/ var, /*MicroLattice*/Element/*!*/ newValue) { + Contract.Requires((newValue != null)); + Contract.Requires((var != null)); + Contract.Requires((element != null)); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + if (!e.IsBottom && !this.microLattice.IsBottom(newValue)) // if we're not at bottom + { + /*MicroLattice*/ + Element currentValue = e[var]; + + if (currentValue == null) { + // No information currently, so we just add the new info. + return e.Add(var, newValue, this.microLattice); + } else { + // Otherwise, take the meet of the new and current info. + //return e.Add(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); + return e.Set(var, this.microLattice.Meet(currentValue, newValue), this.microLattice); + } + } + return e; + } + + public override string/*!*/ ToString(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + Elt e = (Elt)element; + + if (IsTop(e)) { + return ""; + } + if (IsBottom(e)) { + return ""; + } + + int k = 0; + System.Text.StringBuilder buffer = new System.Text.StringBuilder(); + foreach (IVariable/*!*/ key in e.SortedVariables(variableComparer)) { + Contract.Assert(key != null); + if (k++ > 0) { + buffer.Append("; "); + } + buffer.AppendFormat("{0} = {1}", key, e[key]); + } + return buffer.ToString(); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element aValue = a[key]; + Element bValue = b[key]; + + if (aValue != null && bValue != null) { + // Keep only the variables known to both elements. + Element newValue = this.microLattice.Join(aValue, bValue); + newMap = newMap.Add(key, newValue); + } + } + Elt/*!*/ join = new Elt(newMap); + Contract.Assert(join != null); + + // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join)); + + return join; + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element/*!*/ aValue = cce.NonNull(a[key]); + Element bValue = b[key]; + + Element newValue = + bValue == null ? aValue : + this.microLattice.Meet(aValue, bValue); + + newMap = newMap.Add(key, newValue); + } + foreach (IVariable/*!*/ key in b.Variables) { + Contract.Assert(key != null); + Element aValue = a[key]; + Element bValue = b[key]; + Debug.Assert(bValue != null); + + if (aValue == null) { + // It's a variable we didn't cover in the last loop. + newMap = newMap.Add(key, bValue); + } + } + return new Elt(newMap); + } + + /// + /// Perform the pointwise widening of the elements in the map + /// + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires((second != null)); + //Contract.Requires((first != null)); + Contract.Ensures(Contract.Result() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + // Note we have to add those cases as we do not have a "NonTrivialWiden" method + if (a.IsBottom) + return new Elt(b.Constraints); + if (b.IsBottom) + return new Elt(a.Constraints); + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element aValue = a[key]; + Element bValue = b[key]; + + if (aValue != null && bValue != null) { + // Keep only the variables known to both elements. + Element newValue = this.microLattice.Widen(aValue, bValue); + newMap = newMap.Add(key, newValue); + } + } + Element/*!*/ widen = new Elt(newMap); + Contract.Assert(widen != null); + // System.Console.WriteLine("{0} widen {1} = {2} ", this.ToString(a), ToString(b), ToString(widen)); + + return widen; + } + + internal static ISet/**//*!*/ VariablesInExpression(IExpr/*!*/ e, ISet/**//*!*/ ignoreVars) { + Contract.Requires(ignoreVars != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result() != null); + HashSet s = new HashSet(); + + IFunApp f = e as IFunApp; + IFunction lambda = e as IFunction; + + if (e is IVariable) { + if (!ignoreVars.Contains(e)) + s.Add(e); + } else if (f != null) // e is IFunApp + { + foreach (IExpr/*!*/ arg in f.Arguments) { + Contract.Assert(arg != null); + s.AddAll(VariablesInExpression(arg, ignoreVars)); + } + } else if (lambda != null) { + IMutableSet x = new HashSet(1); + x.Add(lambda.Param); + + // Ignore the bound variable + s.AddAll(VariablesInExpression(lambda.Body, cce.NonNull(Set.Union(ignoreVars, x)))); + } else if (e is IUnknown) { + // skip (actually, it would be appropriate to return the universal set of all variables) + } else { + Debug.Assert(false, "case not handled: " + e); + } + return s; + } + + + private static ArrayList/**//*!*/ FindConjuncts(IExpr e) { + Contract.Ensures(Contract.Result() != null); + ArrayList result = new ArrayList(); + + IFunApp f = e as IFunApp; + if (f != null) { + if (f.FunctionSymbol.Equals(Prop.And)) { + foreach (IExpr arg in f.Arguments) { + result.AddRange(FindConjuncts(arg)); + } + } else if (f.FunctionSymbol.Equals(Prop.Or) + || f.FunctionSymbol.Equals(Prop.Implies)) { + // Do nothing. + } else { + result.Add(e); + } + } else { + result.Add(e); + } + + return result; + } + + private static bool IsSimpleEquality(IExpr expr, out IVariable left, out IVariable right) { + Contract.Ensures(!Contract.Result() || Contract.ValueAtReturn(out left) != null && Contract.ValueAtReturn(out right) != null); + left = null; + right = null; + + // See if we have an equality + IFunApp nary = expr as IFunApp; + if (nary == null || !nary.FunctionSymbol.Equals(Value.Eq)) { + return false; + } + + // See if it is an equality of two variables + IVariable idLeft = nary.Arguments[0] as IVariable; + IVariable idRight = nary.Arguments[1] as IVariable; + if (idLeft == null || idRight == null) { + return false; + } + + left = idLeft; + right = idRight; + return true; + } + + /// + /// Returns true iff the expression is in the form var == arithmeticExpr + /// + private static bool IsArithmeticExpr(IExpr/*!*/ expr) { + Contract.Requires(expr != null); + // System.Console.WriteLine("\t\tIsArithmetic called with {0} of type {1}", expr, expr.GetType().ToString()); + + if (expr is IVariable) // expr is a variable + return true; + else if (expr is IFunApp) // may be ==, +, -, /, % or an integer + { + IFunApp fun = (IFunApp)expr; + + if (fun.FunctionSymbol is IntSymbol) // it is an integer + return true; + else if (fun.FunctionSymbol.Equals(Int.Negate)) // it is an unary minus + return IsArithmeticExpr((IExpr/*!*/)cce.NonNull(fun.Arguments[0])); + else if (fun.Arguments.Count != 2) // A function of two or more operands is not arithmetic + return false; + else { + IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + + if (!(left is IVariable || right is IVariable)) // At least one of the two operands must be a variable + return false; + + if (fun.FunctionSymbol.Equals(Value.Eq) + || fun.FunctionSymbol.Equals(Int.Add) + || fun.FunctionSymbol.Equals(Int.Sub) + || fun.FunctionSymbol.Equals(Int.Mul) + || fun.FunctionSymbol.Equals(Int.Div) + || fun.FunctionSymbol.Equals(Int.Mod)) + return IsArithmeticExpr(left) && IsArithmeticExpr(right); + else + return false; + } + } else { + return false; + } + } + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + if (IsTop(element)) { + return propExprFactory.True; + } + if (IsBottom(element)) { + return propExprFactory.False; + } + + Elt e = (Elt)element; + IExpr truth = propExprFactory.True; + IExpr result = truth; + + foreach (IVariable/*!*/ variable in e.SortedVariables(variableComparer)) { + Contract.Assert(variable != null); + Element value = (Element)e[variable]; + + if (value == null || this.microLattice.IsTop(value)) { + continue; + } // Skip variables about which we know nothing. + if (this.microLattice.IsBottom(value)) { + return propExprFactory.False; + } + + IExpr conjunct = this.microLattice.ToPredicate(variable, value); + + result = (result == truth) ? (IExpr)conjunct : (IExpr)propExprFactory.And(result, conjunct); + } + return result; + } + + + public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull((Elt)element).Remove(variable, this.microLattice); + } + + private delegate IExpr/*!*/ OnUnableToInline(IVariable/*!*/ var); + private IExpr/*!*/ IdentityVarToExpr(IVariable/*!*/ var) { + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + return var; + } + + /// + /// Return a new expression in which each variable has been + /// replaced by an expression representing what is known about + /// that variable. + /// + private IExpr/*!*/ InlineVariables(Elt/*!*/ element, IExpr/*!*/ expr, ISet/**//*!*/ notInlineable, + OnUnableToInline/*!*/ unableToInline) { + Contract.Requires(unableToInline != null); + Contract.Requires(notInlineable != null); + Contract.Requires(expr != null); + Contract.Requires(element != null); + Contract.Ensures(Contract.Result() != null); + IVariable var = expr as IVariable; + if (var != null) { + /*MicroLattice*/ + Element value = element[var]; + if (notInlineable.Contains(var) || value == null || this.microLattice.IsTop(value)) { + return unableToInline(var); // We don't know anything about this variable. + } else { + // GetFoldExpr returns null when it can yield an expression that + // can be substituted for the variable. + IExpr valueExpr = this.microLattice.GetFoldExpr(value); + return (valueExpr == null) ? var : valueExpr; + } + } + + // else + + IFunApp fun = expr as IFunApp; + if (fun != null) { + IList newargs = new ArrayList(); + foreach (IExpr/*!*/ arg in fun.Arguments) { + Contract.Assert(arg != null); + newargs.Add(InlineVariables(element, arg, notInlineable, unableToInline)); + } + return fun.CloneWithArguments(newargs); + } + + // else + + IFunction lambda = expr as IFunction; + if (lambda != null) { + IMutableSet x = new HashSet(1); + x.Add(lambda.Param); + + // Don't inline the bound variable + return lambda.CloneWithBody( + InlineVariables(element, lambda.Body, + cce.NonNull(Set.Union(notInlineable, x)), unableToInline) + ); + } + + // else + + if (expr is IUnknown) { + return expr; + } else { + throw + new System.NotImplementedException("cannot inline identifies in expression " + expr); + } + } + + + public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result() != null); + Elt/*!*/ result = (Elt)element; + Contract.Assert(result != null); + + if (IsBottom(element)) { + return result; // == element + } + + expr = InlineVariables(result, expr, cce.NonNull(Set.Empty), new OnUnableToInline(IdentityVarToExpr)); + + foreach (IExpr/*!*/ conjunct in FindConjuncts(expr)) { + Contract.Assert(conjunct != null); + IVariable left, right; + + if (IsSimpleEquality(conjunct, out left, out right)) { + #region The conjunct is a simple equality + + + Contract.Assert(left != null && right != null); + + Element leftValue = result[left], rightValue = result[right]; + if (leftValue == null) { + leftValue = this.microLattice.Top; + } + if (rightValue == null) { + rightValue = this.microLattice.Top; + } + Element newValue = this.microLattice.Meet(leftValue, rightValue); + result = AddConstraint(result, left, newValue); + result = AddConstraint(result, right, newValue); + + #endregion + } else { + ISet/**/ variablesInvolved = VariablesInExpression(conjunct, Set.Empty); + + if (variablesInvolved.Count == 1) { + #region We have just one variable + + IVariable var = null; + foreach (IVariable/*!*/ v in variablesInvolved) { + Contract.Assert(v != null); + var = v; + } // why is there no better way to get the elements? + Contract.Assert(var != null); + Element/*!*/ value = this.microLattice.EvaluatePredicate(conjunct); + result = AddConstraint(result, var, value); + + #endregion + } else if (IsArithmeticExpr(conjunct) && this.microLattice.UnderstandsBasicArithmetics) { + #region We evalaute an arithmetic expression + + IFunApp fun = (IFunApp)conjunct; + if (fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality + { + // get the variable to be assigned + IExpr/*!*/ leftArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + IExpr/*!*/ var = (leftArg is IVariable) ? leftArg : rightArg; + + Element/*!*/ value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints); + Contract.Assert(value != null); + result = AddConstraint(result, (IVariable/*!*/)cce.NonNull(var), value); + } + #endregion + } + } + } + return result; + } + + + public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result() != null); + if (IsBottom(element)) { + return element; + } else { + return ((Elt)element).Rename(oldName, newName, this.microLattice); + } + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f.Equals(Prop.And) || + f.Equals(Value.Eq) || + microLattice.Understands(f, args); + } + + private sealed class EquivalentExprException : CheckedException { + } + private sealed class EquivalentExprInlineCallback { + private readonly IVariable/*!*/ var; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(var != null); + } + + public EquivalentExprInlineCallback(IVariable/*!*/ var) { + Contract.Requires(var != null); + this.var = var; + // base(); + } + + public IExpr/*!*/ ThrowOnUnableToInline(IVariable/*!*/ othervar) + //throws EquivalentExprException; + { + Contract.Requires(othervar != null); + Contract.Ensures(Contract.Result() != null); + Contract.EnsuresOnThrow(true); + if (othervar.Equals(var)) + throw new EquivalentExprException(); + else + return othervar; + } + } + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/**//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + try { + EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var); + return InlineVariables((Elt)e, expr, cce.NonNull(Set.Empty), + new OnUnableToInline(closure.ThrowOnUnableToInline)); + } catch (EquivalentExprException) { + return null; + } + } + + + /// + /// Check to see if the given predicate holds in the given lattice element. + /// + /// TODO: We leave this unimplemented for now and just return maybe. + /// + /// The lattice element. + /// The predicate. + /// Yes, No, or Maybe + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + return Answer.Maybe; + } + + /// + /// Answers a disequality about two variables. The same information could be obtained + /// by asking CheckPredicate, but a different implementation may be simpler and more + /// efficient. + /// + /// TODO: We leave this unimplemented for now and just return maybe. + /// + /// The lattice element. + /// The first variable. + /// The second variable. + /// Yes, No, or Maybe. + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + return Answer.Maybe; + } + + public override void Validate() { + base.Validate(); + microLattice.Validate(); + } + + } +} diff --git a/Source/AIFramework/cce.cs b/Source/AIFramework/cce.cs index ef594484..1e0b12a5 100644 --- a/Source/AIFramework/cce.cs +++ b/Source/AIFramework/cce.cs @@ -1,193 +1,193 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); - } - //[Pure] - //public static bool NonNullElements(VariableSeq collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) { - return iEnumerator != null; - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - //[Pure] - //public static bool IsValid(Microsoft.Dafny.Expression expression) { - // return true; - //} - //public static List toList(PureCollections.Sequence s) { - // List toRet = new List(); - // foreach (T t in s.elems) - // if(t!=null) - // toRet.Add(t); - // return toRet; - //} - - //internal static bool NonNullElements(Set set) { - // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); - //} -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { +using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// +/// A class containing static methods to extend the functionality of Code Contracts +/// + +public static class cce { + //[Pure] + //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(IDictionary collection) { + return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); + } + //[Pure] + //public static bool NonNullElements(VariableSeq collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// + /// For possibly-null lists of non-null elements + /// + /// + /// + /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! + /// + [Pure] + public static bool NonNullElements(IEnumerable collection, bool nullability) { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements(KeyValuePair kvp) { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements(IEnumerator iEnumerator) { + return iEnumerator != null; + } + //[Pure] + //public static bool NonNullElements(Graphing.Graph graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + //[Pure] + //public static bool IsValid(Microsoft.Dafny.Expression expression) { + // return true; + //} + //public static List toList(PureCollections.Sequence s) { + // List toRet = new List(); + // foreach (T t in s.elems) + // if(t!=null) + // toRet.Add(t); + // return toRet; + //} + + //internal static bool NonNullElements(Set set) { + // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); + //} +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { } \ No newline at end of file diff --git a/Source/AbsInt/AbsInt.csproj b/Source/AbsInt/AbsInt.csproj index 69a2667c..47f45f58 100644 --- a/Source/AbsInt/AbsInt.csproj +++ b/Source/AbsInt/AbsInt.csproj @@ -1,296 +1,296 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} - Library - Properties - AbsInt - AbsInt - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for AbsInt.ruleset - true - 4 - false - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - false - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - bin\Debug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - 4 - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - bin\Release\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - 4 - - - true - bin\x86\z3apidebug\ - DEBUG;TRACE - full - x86 - bin\z3apidebug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - Migrated rules for AbsInt.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - true - 4 - false - - - true - bin\x86\Checked\ - DEBUG;TRACE - full - x86 - bin\Debug\AbsInt.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - 4 - false - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - - - 3.5 - - - - - - - - - - - - - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} + Library + Properties + AbsInt + AbsInt + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for AbsInt.ruleset + true + 4 + false + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + bin\Debug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + 4 + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + bin\Release\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + 4 + + + true + bin\x86\z3apidebug\ + DEBUG;TRACE + full + x86 + bin\z3apidebug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + Migrated rules for AbsInt.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + true + 4 + false + + + true + bin\x86\Checked\ + DEBUG;TRACE + full + x86 + bin\Debug\AbsInt.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + 4 + false + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + + + 3.5 + + + + + + + + + + + + + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + {B230A69C-C466-4065-B9C1-84D80E76D802} + Core + + + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} + ParserHelper + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/AbsInt/IntervalDomain.cs b/Source/AbsInt/IntervalDomain.cs index 1ac80970..0d2676f2 100644 --- a/Source/AbsInt/IntervalDomain.cs +++ b/Source/AbsInt/IntervalDomain.cs @@ -1,1180 +1,1180 @@ -using System; -using System.Numerics; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; - -namespace Microsoft.Boogie.AbstractInterpretation -{ - class NativeIntervallDomain : NativeLattice - { - abstract class E_Common : NativeLattice.Element { } - class E_Bottom : E_Common - { - public override Expr ToExpr() { - return Expr.False; - } - } - class E : E_Common - { - public readonly Node N; - public E() { } - public E(Node n) { - N = n; - } - - public override Expr ToExpr() { - Expr expr = Expr.True; - for (var n = N; n != null; n = n.Next) { - expr = BplAnd(expr, n.ToExpr()); - } - return expr; - } - } - public class Node - { - public readonly Variable V; // variable has type bool or int - // For an integer variable (Lo,Hi) indicates Lo <= V < Hi, where Lo==null means no lower bound and Hi==null means no upper bound. - // For a real variable (Lo,Hi) indicates Lo <= V <= Hi, where Lo==null means no lower bound and Hi==null means no upper bound. - // For a boolean variable, (Lo,Hi) is one of: (null,null) for {false,true}, (null,1) for {false}, and (1,null) for {true}. - public readonly BigInteger? Lo; - public readonly BigInteger? Hi; - public Node Next; // always sorted according to StrictlyBefore; readonly after full initialization - [Pure] - public static bool StrictlyBefore(Variable a, Variable b) { - Contract.Assert(a.UniqueId != b.UniqueId || a == b); - return a.UniqueId < b.UniqueId; - } - - Node(Variable v, BigInteger? lo, BigInteger? hi, Node next) { - Contract.Requires(lo != null || hi != null); // don't accept empty constraints - Contract.Requires(next == null || StrictlyBefore(v, next.V)); - V = v; - Lo = lo; - Hi = hi; - Next = next; - } - - /// - /// This constructor leaves Next as null, allowing the caller to fill in Next to finish off the construction. - /// - public Node(Variable v, BigInteger? lo, BigInteger? hi) { - Contract.Requires(lo != null || hi != null); // don't accept empty constraints - V = v; - Lo = lo; - Hi = hi; - } - - /// - /// Returns a Node that has the constraints head.{V,Lo,Hi} plus - /// all the constraints entailed by Nodes reachable from tail. - /// Requires that "head" sorts no later than anything in "tail". - /// Create either returns "head" itself or returns a new Node. - /// - public static Node Create(Node head, Node tail) { - Contract.Requires(head != null); - Contract.Requires(tail == null || !StrictlyBefore(tail.V, head.V)); - Contract.Requires(head != tail); - - if (head.Next == tail) { - return head; - } else if (tail != null && head.V == tail.V) { - // incorporate both constraints into one Node - return new Node(head.V, Max(head.Lo, tail.Lo, true), Min(head.Lo, tail.Lo, true), tail.Next); - } else { - return new Node(head.V, head.Lo, head.Hi, tail); - } - } - - public static void GetBounds(Node n, Variable v, out BigInteger? lo, out BigInteger? hi) { - for (; n != null; n = n.Next) { - if (n.V == v) { - lo = n.Lo; - hi = n.Hi; - return; - } else if (StrictlyBefore(v, n.V)) { - break; - } - } - lo = null; - hi = null; - } - - /// - /// Return the minimum of "a" and "b". If treatNullAsUnit==true, then "null" is - /// interpreted as positive infinity (the unit element of min); otherwise, it is - /// treated as negative infinity (the zero element of min). - /// - public static BigInteger? Min(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { - if (a == null) { - return treatNullAsUnit ? b : a; - } else if (b == null) { - return treatNullAsUnit ? a : b; - } else { - return BigInteger.Min((BigInteger)a, (BigInteger)b); - } - } - - /// - /// Return the maximum of "a" and "b". If treatNullAsUnit==true, then "null" is - /// interpreted as negative infinity (the unit element of max); otherwise, it is - /// treated as positive infinity (the zero element of max). - /// - public static BigInteger? Max(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { - if (a == null) { - return treatNullAsUnit ? b : a; - } else if (b == null) { - return treatNullAsUnit ? a : b; - } else { - return BigInteger.Max((BigInteger)a, (BigInteger)b); - } - } - - public static IEnumerable> Merge(Node a, Node b) { - while (true) { - if (a == null && b == null) { - yield break; - } else if (a == null || b == null) { - yield return new Tuple(a, b); - if (a != null) { a = a.Next; } else { b = b.Next; } - } else if (a.V == b.V) { - yield return new Tuple(a, b); - a = a.Next; b = b.Next; - } else if (StrictlyBefore(a.V, b.V)) { - yield return new Tuple(a, null); - a = a.Next; - } else { - yield return new Tuple(null, b); - b = b.Next; - } - } - } - - public Expr ToExpr() { - if (!V.IsMutable && CommandLineOptions.Clo.InstrumentInfer != CommandLineOptions.InstrumentationPlaces.Everywhere) { - // omit invariants about readonly variables - return Expr.True; - } else if (V.TypedIdent.Type.IsBool) { - if (Lo == null && Hi == null) { - return Expr.True; - } else { - Contract.Assert((Lo == null && (BigInteger)Hi == 1) || (Hi == null && (BigInteger)Lo == 1)); - var ide = new IdentifierExpr(Token.NoToken, V); - return Hi == null ? ide : Expr.Not(ide); - } - } else if (V.TypedIdent.Type.IsInt) { - Expr e = Expr.True; - if (Lo != null && Hi != null && Lo + 1 == Hi) { - // produce an equality - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); - } else { - // produce a (possibly empty) conjunction of inequalities - if (Lo != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); - } - if (Hi != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLt(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); - } - } - return e; - } else { - Contract.Assert(V.TypedIdent.Type.IsReal); - Expr e = Expr.True; - if (Lo != null && Hi != null && Lo == Hi) { - // produce an equality - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); - } else { - // produce a (possibly empty) conjunction of inequalities - if (Lo != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); - } - if (Hi != null) { - var ide = new IdentifierExpr(Token.NoToken, V); - e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); - } - } - return e; - } - } - } - - static Expr NumberToExpr(BigInteger n, Type ty) { - if (n == null) { - return null; - } else if (ty.IsReal) { - return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); - } else { - Contract.Assume(ty.IsInt); - return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); - } - } - - List upThresholds; // invariant: thresholds are sorted - List downThresholds; // invariant: thresholds are sorted - - /// - /// Requires "thresholds" to be sorted. - /// - public NativeIntervallDomain() { - upThresholds = new List(); - downThresholds = new List(); - } - - public override void Specialize(Implementation impl) { - if (impl == null) { - // remove thresholds - upThresholds = new List(); - downThresholds = new List(); - } else { - var tf = new ThresholdFinder(impl); - tf.Find(out downThresholds, out upThresholds); -#if DEBUG_PRINT - Console.Write("DEBUG: for implementation '{0}', setting downs to [", impl.Name); - foreach (var i in downThresholds) { - Console.Write(" {0}", i); - } - Console.Write(" ] and ups to ["); - foreach (var i in upThresholds) { - Console.Write(" {0}", i); - } - Console.WriteLine(" ]"); -#endif - } - base.Specialize(impl); - } - - private E_Common top = new E(); - private E_Common bottom = new E_Bottom(); - - public override Element Top { get { return top; } } - public override Element Bottom { get { return bottom; } } - - public override bool IsTop(Element element) { - var e = element as E; - return e != null && e.N == null; - } - public override bool IsBottom(Element element) { - return element is E_Bottom; - } - - public override bool Below(Element a, Element b) { - if (a is E_Bottom) { - return true; - } else if (b is E_Bottom) { - return false; - } else { - var aa = (E)a; - var bb = (E)b; - // check if every constraint in 'bb' is implied by constraints in 'aa' - foreach (var t in Node.Merge(aa.N, bb.N)) { - var x = t.Item1; - var y = t.Item2; - if (x == null) { - // bb constrains a variable that aa does not - return false; - } else if (y == null) { - // aa constrains a variable that bb does not; that's fine - } else if (y.Lo != null && (x.Lo == null || x.Lo < y.Lo)) { - // bb has a Lo constraint, and either aa has no Lo constraint or it has a weaker Lo constraint - return false; - } else if (y.Hi != null && (x.Hi == null || y.Hi < x.Hi)) { - // bb has a Hi o constraint, and either aa has no Hi constraint or it has a weaker Hi constraint - return false; - } - } - return true; - } - } - - public override Element Meet(Element a, Element b) { - if (a is E_Bottom) { - return a; - } else if (b is E_Bottom) { - return b; - } else { - var aa = (E)a; - var bb = (E)b; - Node head = null; - Node prev = null; - foreach (var t in Node.Merge(aa.N, bb.N)) { - var x = t.Item1; - var y = t.Item2; - Node n; - if (x == null) { - n = new Node(y.V, y.Lo, y.Hi); - } else if (y == null) { - n = new Node(x.V, x.Lo, x.Hi); - } else { - var lo = Node.Max(x.Lo, y.Lo, true); - var hi = Node.Min(x.Hi, y.Hi, true); - // if hi<=lo (or hi - /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. - /// A difference is that the this method returns: - /// let d = Dafny_RoundDown(k); - /// return d == -1 ? null : downThresholds[d]; - /// - BigInteger? RoundDown(BigInteger k) - { - if (downThresholds.Count == 0 || k < downThresholds[0]) { - return null; - } - var i = 0; - var j = downThresholds.Count - 1; - while (i < j) - { - var mid = i + (j - i + 1) / 2; - if (downThresholds[mid] <= k) { - i = mid; - } else { - j = mid - 1; - } - } - return downThresholds[i]; - } - - /// - /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. - /// A difference is that the this method returns: - /// let d = Dafny_RoundUp(k); - /// return d == thresholds.Count ? null : upThresholds[d]; - /// - BigInteger? RoundUp(BigInteger k) - { - if (upThresholds.Count == 0 || upThresholds[upThresholds.Count - 1] < k) { - return null; - } - var i = 0; - var j = upThresholds.Count - 1; - while (i < j) - { - var mid = i + (j - i) / 2; - if (upThresholds[mid] < k) { - i = mid + 1; - } else { - j = mid; - } - } - return upThresholds[i]; - } - - public override Element Constrain(Element element, Expr expr) { - if (element is E_Bottom) { - return element; - } else { - var e = (E)element; - var c = Constraint(expr, e.N); - return c == null ? element : Meet(element, c); - } - } - - /// - /// Returns an Element that corresponds to the constraints implied by "expr" in the - /// state "state". - /// Return "null" to indicate no constraints. - /// - E_Common Constraint(Expr expr, Node state) { - Variable v; - if (IsVariable(expr, out v)) { - var n = new Node(v, BigInteger.One, null); - return new E(n); - } else if (expr is LiteralExpr) { - var e = (LiteralExpr)expr; - return (bool)e.Val ? null : new E_Bottom(); - } else if (expr is NAryExpr) { - var e = (NAryExpr)expr; - if (e.Fun is UnaryOperator) { - if (((UnaryOperator)e.Fun).Op == UnaryOperator.Opcode.Not) { - if (IsVariable(e.Args[0], out v)) { - var n = new Node(v, null, BigInteger.One); - return new E(n); - } - } - } else if (e.Fun is BinaryOperator) { - var op = ((BinaryOperator)e.Fun).Op; - var arg0 = e.Args[0]; - var arg1 = e.Args[1]; - switch (op) { - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Iff: { - E_Common c = null; - if (IsVariable(arg0, out v)) { - BigInteger? lo, hi; - if (PartiallyEvaluate(arg1, state, out lo, out hi)) { - var n = new Node(v, lo, hi); - c = new E(n); - } - } - if (IsVariable(arg1, out v)) { - BigInteger? lo, hi; - if (PartiallyEvaluate(arg1, state, out lo, out hi)) { - var n = new Node(v, lo, hi); - c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); - } - } - return c; - } - case BinaryOperator.Opcode.Neq: { - E_Common c = null; - if (IsVariable(arg0, out v)) { - c = ConstrainNeq(state, v, arg1); - } - if (IsVariable(arg1, out v)) { - var cc = ConstrainNeq(state, v, arg0); - if (cc != null) { - c = c == null ? cc : (E_Common)Meet(c, cc); - } - } - return c; - } - case BinaryOperator.Opcode.Le: { - E_Common c = null; - if (IsVariable(arg1, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg0, state, out lo, out hi); - if (lo != null) { - var n = new Node(v, lo, null); - c = new E(n); - } - } - if (IsVariable(arg0, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg1, state, out lo, out hi); - if (hi != null) { - var n = new Node(v, null, hi); - c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); - } - } - return c; - } - case BinaryOperator.Opcode.Lt: { - E_Common c = null; - if (IsVariable(arg1, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg0, state, out lo, out hi); - if (lo != null) { - var n = new Node(v, v.TypedIdent.Type.IsReal ? lo : lo + 1, null); - c = new E(n); - } - } - if (IsVariable(arg0, out v)) { - BigInteger? lo, hi; - PartiallyEvaluate(arg1, state, out lo, out hi); - if (hi != null) { - var n = new Node(v, null, v.TypedIdent.Type.IsReal ? hi : hi - 1); - c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); - } - } - return c; - } - case BinaryOperator.Opcode.Ge: { - var tmp = arg0; arg0 = arg1; arg1 = tmp; - goto case BinaryOperator.Opcode.Le; - } - case BinaryOperator.Opcode.Gt: { - var tmp = arg0; arg0 = arg1; arg1 = tmp; - goto case BinaryOperator.Opcode.Lt; - } - default: - break; - } - } - } - return null; // approximation - } - - private E ConstrainNeq(Node state, Variable v, Expr arg) { - BigInteger? lo, hi; - if (PartiallyEvaluate(arg, state, out lo, out hi)) { - if (!v.TypedIdent.Type.IsReal && lo != null && hi != null && lo + 1 == hi) { - var exclude = lo; - // If the partially evaluated arg (whose value is "exclude") is an end-point of - // the interval known for "v", then produce a constraint that excludes that bound. - Node.GetBounds(state, v, out lo, out hi); - if (lo != null && lo == exclude) { - var n = new Node(v, lo + 1, null); - return new E(n); - } else if (hi != null && exclude + 1 == hi) { - var n = new Node(v, null, exclude); - return new E(n); - } - } - } - return null; - } - - bool IsVariable(Expr expr, out Variable v) { - var e = expr as IdentifierExpr; - if (e == null) { - v = null; - return false; - } else { - v = e.Decl; - return true; - } - } - - public override Element Update(Element element, AssignCmd cmd) { - if (element is E_Bottom) { - return element; - } - var e = (E)element; - var nn = e.N; - Contract.Assert(cmd.Lhss.Count == cmd.Rhss.Count); - for (int i = 0; i < cmd.Lhss.Count; i++) { - var lhs = cmd.Lhss[i]; - var rhs = cmd.Rhss[i]; - BigInteger? lo; - BigInteger? hi; - PartiallyEvaluate(rhs, e.N, out lo, out hi); - nn = UpdateOne(nn, lhs.DeepAssignedVariable, lo, hi); - } - return new E(nn); - } - - bool PartiallyEvaluate(Expr rhs, Node node, out BigInteger? lo, out BigInteger? hi) { - var pe = new PEVisitor(node); - pe.VisitExpr(rhs); - lo = pe.Lo; - hi = pe.Hi; - return lo != null || hi != null; - } - - class PEVisitor : ReadOnlyVisitor - { - public BigInteger? Lo; - public BigInteger? Hi; - - readonly BigInteger one = BigInteger.One; - - Node N; - public PEVisitor(Node n) { - N = n; - } - - // Override visitors for all expressions that can return a boolean, integer, or real result - - public override Expr VisitExpr(Expr node) { - Lo = Hi = null; - return base.VisitExpr(node); - } - public override Expr VisitLiteralExpr(LiteralExpr node) { - if (node.Val is BigNum) { - var n = ((BigNum)node.Val).ToBigInteger; - Lo = n; - Hi = n + 1; - } else if (node.Val is BigDec) { - BigInteger floor, ceiling; - ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); - Lo = floor; - Hi = ceiling; - } else if (node.Val is bool) { - if ((bool)node.Val) { - // true - Lo = one; - Hi = null; - } else { - // false - Lo = null; - Hi = one; - } - } - return node; - } - public override Expr VisitIdentifierExpr(IdentifierExpr node) { - if (node.Type.IsBool || node.Type.IsInt || node.Type.IsReal) { - Node.GetBounds(N, node.Decl, out Lo, out Hi); - } - return node; - } - public override Expr VisitNAryExpr(NAryExpr node) { - if (node.Fun is UnaryOperator) { - var op = (UnaryOperator)node.Fun; - Contract.Assert(node.Args.Count == 1); - if (op.Op == UnaryOperator.Opcode.Neg) { - BigInteger? lo, hi; - VisitExpr(node.Args[0]); - lo = Lo; hi = Hi; - if (hi != null) { - Lo = node.Type.IsReal ? -hi : 1 - hi; - } - if (lo != null) { - Hi = node.Type.IsReal ? -lo : 1 - lo; - } - } - else if (op.Op == UnaryOperator.Opcode.Not) { - VisitExpr(node.Args[0]); - Contract.Assert((Lo == null && Hi == null) || - (Lo == null && (BigInteger)Hi == 1) || - (Hi == null && (BigInteger)Lo == 1)); - var tmp = Lo; - Lo = Hi; - Hi = tmp; - } - } else if (node.Fun is BinaryOperator) { - var op = (BinaryOperator)node.Fun; - Contract.Assert(node.Args.Count == 2); - BigInteger? lo0, hi0, lo1, hi1; - VisitExpr(node.Args[0]); - lo0 = Lo; hi0 = Hi; - VisitExpr(node.Args[1]); - lo1 = Lo; hi1 = Hi; - Lo = Hi = null; - var isReal = node.Args[0].Type.IsReal; - switch (op.Op) { - case BinaryOperator.Opcode.And: - if (hi0 != null || hi1 != null) { - // one operand is definitely false, thus so is the result - Lo = null; Hi = one; - } else if (lo0 != null && lo1 != null) { - // both operands are definitely true, thus so is the result - Lo = one; Hi = null; - } - break; - case BinaryOperator.Opcode.Or: - if (lo0 != null || lo1 != null) { - // one operand is definitely true, thus so is the result - Lo = one; Hi = null; - } else if (hi0 != null && hi1 != null) { - // both operands are definitely false, thus so is the result - Lo = null; Hi = one; - } - break; - case BinaryOperator.Opcode.Imp: - if (hi0 != null || lo1 != null) { - // either arg0 false or arg1 is true, so the result is true - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null) { - // arg0 is true and arg1 is false, so the result is false - Lo = null; Hi = one; - } - break; - case BinaryOperator.Opcode.Iff: - if (lo0 != null && lo1 != null) { - Lo = one; Hi = null; - } else if (hi0 != null && hi1 != null) { - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null) { - Lo = null; Hi = one; - } else if (hi0 != null && lo1 != null) { - Lo = null; Hi = one; - } - if (op.Op == BinaryOperator.Opcode.Neq) { - var tmp = Lo; Lo = Hi; Hi = tmp; - } - break; - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Neq: - if (node.Args[0].Type.IsBool) { - goto case BinaryOperator.Opcode.Iff; - } - // For Eq: - // If the (lo0,hi0) and (lo1,hi1) ranges do not overlap, the answer is false. - // If both ranges are the same unit range, then the answer is true. - if (hi0 != null && lo1 != null && (isReal ? hi0 < lo1 : hi0 <= lo1)) { - // no overlap - Lo = null; Hi = one; - } else if (lo0 != null && hi1 != null && (isReal ? hi1 < lo0 : hi1 <= lo0)) { - Lo = null; Hi = one; - // no overlaop - } else if (lo0 != null && hi0 != null && lo1 != null && hi1 != null && - lo0 == lo1 && hi0 == hi1 && // ranges are the same - (isReal ? lo0 == hi0 : lo0 + 1 == hi0)) { // unit range - // both ranges are the same unit range - Lo = one; Hi = null; - } - if (op.Op == BinaryOperator.Opcode.Neq) { - var tmp = Lo; Lo = Hi; Hi = tmp; - } - break; - case BinaryOperator.Opcode.Le: - if (isReal) { - // If hi0 <= lo1, then the answer is true. - // If hi1 < lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 <= lo1) { - Lo = one; Hi = null; - } else if (hi1 != null && lo0 != null && hi1 < lo0) { - Lo = null; Hi = one; - } - } else { - // If hi0 - 1 <= lo1, then the answer is true. - // If hi1 <= lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 - 1 <= lo1) { - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null && hi1 <= lo0) { - Lo = null; Hi = one; - } - } - break; - case BinaryOperator.Opcode.Lt: - if (isReal) { - // If hi0 < lo1, then the answer is true. - // If hi1 <= lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 < lo1) { - Lo = one; Hi = null; - } else if (hi1 != null && lo0 != null && hi1 <= lo0) { - Lo = null; Hi = one; - } - } else { - // If hi0 <= lo1, then the answer is true. - // If hi1 - 1 <= lo0, then the answer is false. - if (hi0 != null && lo1 != null && hi0 <= lo1) { - Lo = one; Hi = null; - } else if (lo0 != null && hi1 != null && hi1 - 1 <= lo0) { - Lo = null; Hi = one; - } - } - break; - case BinaryOperator.Opcode.Gt: - // swap the operands and then continue as Lt - { - var tmp = lo0; lo0 = lo1; lo1 = tmp; - tmp = hi0; hi0 = hi1; hi1 = tmp; - } - goto case BinaryOperator.Opcode.Lt; - case BinaryOperator.Opcode.Ge: - // swap the operands and then continue as Le - { - var tmp = lo0; lo0 = lo1; lo1 = tmp; - tmp = hi0; hi0 = hi1; hi1 = tmp; - } - goto case BinaryOperator.Opcode.Le; - case BinaryOperator.Opcode.Add: - if (lo0 != null && lo1 != null) { - Lo = lo0 + lo1; - } - if (hi0 != null && hi1 != null) { - Hi = isReal ? hi0 + hi1 : hi0 + hi1 - 1; - } - break; - case BinaryOperator.Opcode.Sub: - if (lo0 != null && hi1 != null) { - Lo = isReal ? lo0 - hi1 : lo0 - hi1 + 1; - } - if (hi0 != null && lo1 != null) { - Hi = hi0 - lo1; - } - break; - case BinaryOperator.Opcode.Mul: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null) { - if (0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = lo0 * lo1; - Hi = hi0 == null || hi1 == null ? null : isReal ? hi0 * hi1 : (hi0 - 1) * (hi1 - 1) + 1; - } else if ((BigInteger)lo0 < 0 && (BigInteger)lo1 < 0) { - Lo = null; // approximation - Hi = isReal ? lo0 * lo1 : lo0 * lo1 + 1; - } - } - break; - case BinaryOperator.Opcode.Div: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = BigInteger.Zero; - Hi = hi0; - } - break; - case BinaryOperator.Opcode.Mod: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = BigInteger.Zero; - Hi = hi1; - } - break; - case BinaryOperator.Opcode.RealDiv: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = BigInteger.Zero; - Hi = 1 <= (BigInteger)lo1 ? hi0 : null; - } - break; - case BinaryOperator.Opcode.Pow: - // this uses an incomplete approximation that could be tightened up - if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { - Lo = 1 <= (BigInteger)lo1 ? BigInteger.One : BigInteger.Zero; - Hi = hi1; - } - break; - default: - break; - } - } else if (node.Fun is IfThenElse) { - var op = (IfThenElse)node.Fun; - Contract.Assert(node.Args.Count == 3); - BigInteger? guardLo, guardHi, lo0, hi0, lo1, hi1; - VisitExpr(node.Args[0]); - guardLo = Lo; guardHi = Hi; - VisitExpr(node.Args[1]); - lo0 = Lo; hi0 = Hi; - VisitExpr(node.Args[2]); - lo1 = Lo; hi1 = Hi; - Contract.Assert(guardLo == null || guardHi == null); // this is a consequence of the guard being boolean - if (guardLo != null) { - // guard is always true - Lo = lo0; Hi = hi0; - } else if (guardHi != null) { - // guard is always false - Lo = lo1; Hi = hi1; - } else { - // we don't know which branch will be taken, so join the information from the two branches - Lo = Node.Min(lo0, lo1, false); - Hi = Node.Max(hi0, hi1, false); - } - } else if (node.Fun is FunctionCall) { - var call = (FunctionCall)node.Fun; - // See if this is an identity function, which we do by checking: that the function has - // exactly one argument and the function has been marked by the user with the attribute {:identity} - bool claimsToBeIdentity = false; - if (call.ArgumentCount == 1 && call.Func.CheckBooleanAttribute("identity", ref claimsToBeIdentity) && claimsToBeIdentity && node.Args[0].Type.Equals(node.Type)) { - VisitExpr(node.Args[0]); - } - } - return node; - } - public override BinderExpr VisitBinderExpr(BinderExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitOldExpr(OldExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitCodeExpr(CodeExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitBvConcatExpr(BvConcatExpr node) { - // don't recurse on subexpression - return node; - } - public override Expr VisitBvExtractExpr(BvExtractExpr node) { - // don't recurse on subexpression - return node; - } - } - - public override Element Eliminate(Element element, Variable v) { - if (element is E_Bottom) { - return element; - } - var e = (E)element; - var nn = UpdateOne(e.N, v, null, null); - if (nn == e.N) { - return element; - } else { - return new E(nn); - } - } - - Node UpdateOne(Node nn, Variable v, BigInteger? lo, BigInteger? hi) { - var orig = nn; - Node head = null; - Node prev = null; - var foundV = false; - for (; nn != null && !Node.StrictlyBefore(v, nn.V); nn = nn.Next) { - if (nn.V == v) { - foundV = true; - nn = nn.Next; - break; // we found the place where the new node goes - } else { - var n = new Node(nn.V, nn.Lo, nn.Hi); // copy this Node - if (head == null) { - head = n; - } else { - prev.Next = n; - } - prev = n; - } - } - Node rest; - if (lo == null && hi == null) { - // eliminate all information about "v" - if (!foundV) { - return orig; - } - rest = nn; - } else { - rest = new Node(v, lo, hi); - rest.Next = nn; - } - if (head == null) { - head = rest; - } else { - prev.Next = rest; - } - return head; - } - - /// - /// Return a resolved/type-checked expression that represents the conjunction of a and b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplAnd(Expr a, Expr b) { - if (a == Expr.True) { - return b; - } else if (b == Expr.True) { - return a; - } else { - var nary = Expr.Binary(BinaryOperator.Opcode.And, a, b); - nary.Type = Type.Bool; - nary.TypeParameters = SimpleTypeParamInstantiation.EMPTY; - return nary; - } - } - - /// - /// Return a resolved/type-checked expression that represents a EQUALS b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplEq(Expr a, Expr b) { - var e = Expr.Eq(a, b); - e.Type = Type.Bool; - return e; - } - - /// - /// Return a resolved/type-checked expression that represents a LESS-EQUAL b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplLe(Expr a, Expr b) { - var e = Expr.Le(a, b); - e.Type = Type.Bool; - return e; - } - /// - /// Return a resolved/type-checked expression that represents a LESS b. - /// Requires a and b to be resolved and type checked already. - /// - public static Expr BplLt(Expr a, Expr b) { - var e = Expr.Lt(a, b); - e.Type = Type.Bool; - return e; - } - } - - public class ThresholdFinder : ReadOnlyVisitor - { - readonly Implementation Impl; - public ThresholdFinder(Implementation impl) { - Contract.Requires(impl != null); - Impl = impl; - } - HashSet downs = new HashSet(); - HashSet ups = new HashSet(); - public void Find(out List downThresholds, out List upThresholds) { - // always include -1, 0, 1 as down-thresholds - downs.Clear(); - downs.Add(-1); - downs.Add(0); - downs.Add(1); - // always include 0 and 1 as up-thresholds - ups.Clear(); - ups.Add(0); - ups.Add(1); - - foreach (Requires p in Impl.Proc.Requires) { - Visit(p.Condition); - } - foreach (Ensures p in Impl.Proc.Ensures) { - Visit(p.Condition); - } - foreach (var b in Impl.Blocks) { - foreach (Cmd c in b.Cmds) { - Visit(c); - } - } - - // convert the HashSets to sorted Lists and return - downThresholds = new List(); - foreach (var i in downs) { - downThresholds.Add(i); - } - downThresholds.Sort(); - upThresholds = new List(); - foreach (var i in ups) { - upThresholds.Add(i); - } - upThresholds.Sort(); - } - - public override Expr VisitNAryExpr(NAryExpr node) { - if (node.Fun is BinaryOperator) { - var op = (BinaryOperator)node.Fun; - Contract.Assert(node.Args.Count == 2); - var arg0 = node.Args[0]; - var arg1 = node.Args[1]; - var offset = arg0.Type.IsReal ? 0 : 1; - BigInteger? k; - switch (op.Op) { - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Neq: - k = AsIntLiteral(arg0); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i - 1); - downs.Add(i); - ups.Add(i + 1); - ups.Add(i + 2); - } - k = AsIntLiteral(arg1); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i - 1); - downs.Add(i); - ups.Add(i + 1); - ups.Add(i + 2); - } - break; - case BinaryOperator.Opcode.Le: - k = AsIntLiteral(arg0); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i - 1); - downs.Add(i); - } - k = AsIntLiteral(arg1); - if (k != null) { - var i = (BigInteger)k; - ups.Add(i + offset); - ups.Add(i + 1 + offset); - } - break; - case BinaryOperator.Opcode.Lt: - k = AsIntLiteral(arg0); - if (k != null) { - var i = (BigInteger)k; - downs.Add(i ); - downs.Add(i + 1); - } - k = AsIntLiteral(arg1); - if (k != null) { - var i = (BigInteger)k; - ups.Add(i - 1 + offset); - ups.Add(i + offset); - } - break; - case BinaryOperator.Opcode.Ge: - { var tmp = arg0; arg0 = arg1; arg1 = tmp; } - goto case BinaryOperator.Opcode.Le; - case BinaryOperator.Opcode.Gt: - { var tmp = arg0; arg0 = arg1; arg1 = tmp; } - goto case BinaryOperator.Opcode.Lt; - default: - break; - } - } - return base.VisitNAryExpr(node); - } - - BigInteger? AsIntLiteral(Expr e) { - var lit = e as LiteralExpr; - if (lit != null && lit.isBigNum) { - BigNum bn = lit.asBigNum; - return bn.ToBigInteger; - } - return null; - } - } - -} +using System; +using System.Numerics; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; + +namespace Microsoft.Boogie.AbstractInterpretation +{ + class NativeIntervallDomain : NativeLattice + { + abstract class E_Common : NativeLattice.Element { } + class E_Bottom : E_Common + { + public override Expr ToExpr() { + return Expr.False; + } + } + class E : E_Common + { + public readonly Node N; + public E() { } + public E(Node n) { + N = n; + } + + public override Expr ToExpr() { + Expr expr = Expr.True; + for (var n = N; n != null; n = n.Next) { + expr = BplAnd(expr, n.ToExpr()); + } + return expr; + } + } + public class Node + { + public readonly Variable V; // variable has type bool or int + // For an integer variable (Lo,Hi) indicates Lo <= V < Hi, where Lo==null means no lower bound and Hi==null means no upper bound. + // For a real variable (Lo,Hi) indicates Lo <= V <= Hi, where Lo==null means no lower bound and Hi==null means no upper bound. + // For a boolean variable, (Lo,Hi) is one of: (null,null) for {false,true}, (null,1) for {false}, and (1,null) for {true}. + public readonly BigInteger? Lo; + public readonly BigInteger? Hi; + public Node Next; // always sorted according to StrictlyBefore; readonly after full initialization + [Pure] + public static bool StrictlyBefore(Variable a, Variable b) { + Contract.Assert(a.UniqueId != b.UniqueId || a == b); + return a.UniqueId < b.UniqueId; + } + + Node(Variable v, BigInteger? lo, BigInteger? hi, Node next) { + Contract.Requires(lo != null || hi != null); // don't accept empty constraints + Contract.Requires(next == null || StrictlyBefore(v, next.V)); + V = v; + Lo = lo; + Hi = hi; + Next = next; + } + + /// + /// This constructor leaves Next as null, allowing the caller to fill in Next to finish off the construction. + /// + public Node(Variable v, BigInteger? lo, BigInteger? hi) { + Contract.Requires(lo != null || hi != null); // don't accept empty constraints + V = v; + Lo = lo; + Hi = hi; + } + + /// + /// Returns a Node that has the constraints head.{V,Lo,Hi} plus + /// all the constraints entailed by Nodes reachable from tail. + /// Requires that "head" sorts no later than anything in "tail". + /// Create either returns "head" itself or returns a new Node. + /// + public static Node Create(Node head, Node tail) { + Contract.Requires(head != null); + Contract.Requires(tail == null || !StrictlyBefore(tail.V, head.V)); + Contract.Requires(head != tail); + + if (head.Next == tail) { + return head; + } else if (tail != null && head.V == tail.V) { + // incorporate both constraints into one Node + return new Node(head.V, Max(head.Lo, tail.Lo, true), Min(head.Lo, tail.Lo, true), tail.Next); + } else { + return new Node(head.V, head.Lo, head.Hi, tail); + } + } + + public static void GetBounds(Node n, Variable v, out BigInteger? lo, out BigInteger? hi) { + for (; n != null; n = n.Next) { + if (n.V == v) { + lo = n.Lo; + hi = n.Hi; + return; + } else if (StrictlyBefore(v, n.V)) { + break; + } + } + lo = null; + hi = null; + } + + /// + /// Return the minimum of "a" and "b". If treatNullAsUnit==true, then "null" is + /// interpreted as positive infinity (the unit element of min); otherwise, it is + /// treated as negative infinity (the zero element of min). + /// + public static BigInteger? Min(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { + if (a == null) { + return treatNullAsUnit ? b : a; + } else if (b == null) { + return treatNullAsUnit ? a : b; + } else { + return BigInteger.Min((BigInteger)a, (BigInteger)b); + } + } + + /// + /// Return the maximum of "a" and "b". If treatNullAsUnit==true, then "null" is + /// interpreted as negative infinity (the unit element of max); otherwise, it is + /// treated as positive infinity (the zero element of max). + /// + public static BigInteger? Max(BigInteger? a, BigInteger? b, bool treatNullAsUnit) { + if (a == null) { + return treatNullAsUnit ? b : a; + } else if (b == null) { + return treatNullAsUnit ? a : b; + } else { + return BigInteger.Max((BigInteger)a, (BigInteger)b); + } + } + + public static IEnumerable> Merge(Node a, Node b) { + while (true) { + if (a == null && b == null) { + yield break; + } else if (a == null || b == null) { + yield return new Tuple(a, b); + if (a != null) { a = a.Next; } else { b = b.Next; } + } else if (a.V == b.V) { + yield return new Tuple(a, b); + a = a.Next; b = b.Next; + } else if (StrictlyBefore(a.V, b.V)) { + yield return new Tuple(a, null); + a = a.Next; + } else { + yield return new Tuple(null, b); + b = b.Next; + } + } + } + + public Expr ToExpr() { + if (!V.IsMutable && CommandLineOptions.Clo.InstrumentInfer != CommandLineOptions.InstrumentationPlaces.Everywhere) { + // omit invariants about readonly variables + return Expr.True; + } else if (V.TypedIdent.Type.IsBool) { + if (Lo == null && Hi == null) { + return Expr.True; + } else { + Contract.Assert((Lo == null && (BigInteger)Hi == 1) || (Hi == null && (BigInteger)Lo == 1)); + var ide = new IdentifierExpr(Token.NoToken, V); + return Hi == null ? ide : Expr.Not(ide); + } + } else if (V.TypedIdent.Type.IsInt) { + Expr e = Expr.True; + if (Lo != null && Hi != null && Lo + 1 == Hi) { + // produce an equality + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); + } else { + // produce a (possibly empty) conjunction of inequalities + if (Lo != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); + } + if (Hi != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLt(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); + } + } + return e; + } else { + Contract.Assert(V.TypedIdent.Type.IsReal); + Expr e = Expr.True; + if (Lo != null && Hi != null && Lo == Hi) { + // produce an equality + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplEq(ide, NumberToExpr((BigInteger)Lo, V.TypedIdent.Type))); + } else { + // produce a (possibly empty) conjunction of inequalities + if (Lo != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(NumberToExpr((BigInteger)Lo, V.TypedIdent.Type), ide)); + } + if (Hi != null) { + var ide = new IdentifierExpr(Token.NoToken, V); + e = Expr.And(e, BplLe(ide, NumberToExpr((BigInteger)Hi, V.TypedIdent.Type))); + } + } + return e; + } + } + } + + static Expr NumberToExpr(BigInteger n, Type ty) { + if (n == null) { + return null; + } else if (ty.IsReal) { + return Expr.Literal(Basetypes.BigDec.FromBigInt(n)); + } else { + Contract.Assume(ty.IsInt); + return Expr.Literal(Basetypes.BigNum.FromBigInt(n)); + } + } + + List upThresholds; // invariant: thresholds are sorted + List downThresholds; // invariant: thresholds are sorted + + /// + /// Requires "thresholds" to be sorted. + /// + public NativeIntervallDomain() { + upThresholds = new List(); + downThresholds = new List(); + } + + public override void Specialize(Implementation impl) { + if (impl == null) { + // remove thresholds + upThresholds = new List(); + downThresholds = new List(); + } else { + var tf = new ThresholdFinder(impl); + tf.Find(out downThresholds, out upThresholds); +#if DEBUG_PRINT + Console.Write("DEBUG: for implementation '{0}', setting downs to [", impl.Name); + foreach (var i in downThresholds) { + Console.Write(" {0}", i); + } + Console.Write(" ] and ups to ["); + foreach (var i in upThresholds) { + Console.Write(" {0}", i); + } + Console.WriteLine(" ]"); +#endif + } + base.Specialize(impl); + } + + private E_Common top = new E(); + private E_Common bottom = new E_Bottom(); + + public override Element Top { get { return top; } } + public override Element Bottom { get { return bottom; } } + + public override bool IsTop(Element element) { + var e = element as E; + return e != null && e.N == null; + } + public override bool IsBottom(Element element) { + return element is E_Bottom; + } + + public override bool Below(Element a, Element b) { + if (a is E_Bottom) { + return true; + } else if (b is E_Bottom) { + return false; + } else { + var aa = (E)a; + var bb = (E)b; + // check if every constraint in 'bb' is implied by constraints in 'aa' + foreach (var t in Node.Merge(aa.N, bb.N)) { + var x = t.Item1; + var y = t.Item2; + if (x == null) { + // bb constrains a variable that aa does not + return false; + } else if (y == null) { + // aa constrains a variable that bb does not; that's fine + } else if (y.Lo != null && (x.Lo == null || x.Lo < y.Lo)) { + // bb has a Lo constraint, and either aa has no Lo constraint or it has a weaker Lo constraint + return false; + } else if (y.Hi != null && (x.Hi == null || y.Hi < x.Hi)) { + // bb has a Hi o constraint, and either aa has no Hi constraint or it has a weaker Hi constraint + return false; + } + } + return true; + } + } + + public override Element Meet(Element a, Element b) { + if (a is E_Bottom) { + return a; + } else if (b is E_Bottom) { + return b; + } else { + var aa = (E)a; + var bb = (E)b; + Node head = null; + Node prev = null; + foreach (var t in Node.Merge(aa.N, bb.N)) { + var x = t.Item1; + var y = t.Item2; + Node n; + if (x == null) { + n = new Node(y.V, y.Lo, y.Hi); + } else if (y == null) { + n = new Node(x.V, x.Lo, x.Hi); + } else { + var lo = Node.Max(x.Lo, y.Lo, true); + var hi = Node.Min(x.Hi, y.Hi, true); + // if hi<=lo (or hi + /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. + /// A difference is that the this method returns: + /// let d = Dafny_RoundDown(k); + /// return d == -1 ? null : downThresholds[d]; + /// + BigInteger? RoundDown(BigInteger k) + { + if (downThresholds.Count == 0 || k < downThresholds[0]) { + return null; + } + var i = 0; + var j = downThresholds.Count - 1; + while (i < j) + { + var mid = i + (j - i + 1) / 2; + if (downThresholds[mid] <= k) { + i = mid; + } else { + j = mid - 1; + } + } + return downThresholds[i]; + } + + /// + /// For a proof of correctness of this method, see Test/dafny2/Intervals.dfy. + /// A difference is that the this method returns: + /// let d = Dafny_RoundUp(k); + /// return d == thresholds.Count ? null : upThresholds[d]; + /// + BigInteger? RoundUp(BigInteger k) + { + if (upThresholds.Count == 0 || upThresholds[upThresholds.Count - 1] < k) { + return null; + } + var i = 0; + var j = upThresholds.Count - 1; + while (i < j) + { + var mid = i + (j - i) / 2; + if (upThresholds[mid] < k) { + i = mid + 1; + } else { + j = mid; + } + } + return upThresholds[i]; + } + + public override Element Constrain(Element element, Expr expr) { + if (element is E_Bottom) { + return element; + } else { + var e = (E)element; + var c = Constraint(expr, e.N); + return c == null ? element : Meet(element, c); + } + } + + /// + /// Returns an Element that corresponds to the constraints implied by "expr" in the + /// state "state". + /// Return "null" to indicate no constraints. + /// + E_Common Constraint(Expr expr, Node state) { + Variable v; + if (IsVariable(expr, out v)) { + var n = new Node(v, BigInteger.One, null); + return new E(n); + } else if (expr is LiteralExpr) { + var e = (LiteralExpr)expr; + return (bool)e.Val ? null : new E_Bottom(); + } else if (expr is NAryExpr) { + var e = (NAryExpr)expr; + if (e.Fun is UnaryOperator) { + if (((UnaryOperator)e.Fun).Op == UnaryOperator.Opcode.Not) { + if (IsVariable(e.Args[0], out v)) { + var n = new Node(v, null, BigInteger.One); + return new E(n); + } + } + } else if (e.Fun is BinaryOperator) { + var op = ((BinaryOperator)e.Fun).Op; + var arg0 = e.Args[0]; + var arg1 = e.Args[1]; + switch (op) { + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Iff: { + E_Common c = null; + if (IsVariable(arg0, out v)) { + BigInteger? lo, hi; + if (PartiallyEvaluate(arg1, state, out lo, out hi)) { + var n = new Node(v, lo, hi); + c = new E(n); + } + } + if (IsVariable(arg1, out v)) { + BigInteger? lo, hi; + if (PartiallyEvaluate(arg1, state, out lo, out hi)) { + var n = new Node(v, lo, hi); + c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); + } + } + return c; + } + case BinaryOperator.Opcode.Neq: { + E_Common c = null; + if (IsVariable(arg0, out v)) { + c = ConstrainNeq(state, v, arg1); + } + if (IsVariable(arg1, out v)) { + var cc = ConstrainNeq(state, v, arg0); + if (cc != null) { + c = c == null ? cc : (E_Common)Meet(c, cc); + } + } + return c; + } + case BinaryOperator.Opcode.Le: { + E_Common c = null; + if (IsVariable(arg1, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg0, state, out lo, out hi); + if (lo != null) { + var n = new Node(v, lo, null); + c = new E(n); + } + } + if (IsVariable(arg0, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg1, state, out lo, out hi); + if (hi != null) { + var n = new Node(v, null, hi); + c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); + } + } + return c; + } + case BinaryOperator.Opcode.Lt: { + E_Common c = null; + if (IsVariable(arg1, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg0, state, out lo, out hi); + if (lo != null) { + var n = new Node(v, v.TypedIdent.Type.IsReal ? lo : lo + 1, null); + c = new E(n); + } + } + if (IsVariable(arg0, out v)) { + BigInteger? lo, hi; + PartiallyEvaluate(arg1, state, out lo, out hi); + if (hi != null) { + var n = new Node(v, null, v.TypedIdent.Type.IsReal ? hi : hi - 1); + c = c == null ? new E(n) : (E_Common)Meet(c, new E(n)); + } + } + return c; + } + case BinaryOperator.Opcode.Ge: { + var tmp = arg0; arg0 = arg1; arg1 = tmp; + goto case BinaryOperator.Opcode.Le; + } + case BinaryOperator.Opcode.Gt: { + var tmp = arg0; arg0 = arg1; arg1 = tmp; + goto case BinaryOperator.Opcode.Lt; + } + default: + break; + } + } + } + return null; // approximation + } + + private E ConstrainNeq(Node state, Variable v, Expr arg) { + BigInteger? lo, hi; + if (PartiallyEvaluate(arg, state, out lo, out hi)) { + if (!v.TypedIdent.Type.IsReal && lo != null && hi != null && lo + 1 == hi) { + var exclude = lo; + // If the partially evaluated arg (whose value is "exclude") is an end-point of + // the interval known for "v", then produce a constraint that excludes that bound. + Node.GetBounds(state, v, out lo, out hi); + if (lo != null && lo == exclude) { + var n = new Node(v, lo + 1, null); + return new E(n); + } else if (hi != null && exclude + 1 == hi) { + var n = new Node(v, null, exclude); + return new E(n); + } + } + } + return null; + } + + bool IsVariable(Expr expr, out Variable v) { + var e = expr as IdentifierExpr; + if (e == null) { + v = null; + return false; + } else { + v = e.Decl; + return true; + } + } + + public override Element Update(Element element, AssignCmd cmd) { + if (element is E_Bottom) { + return element; + } + var e = (E)element; + var nn = e.N; + Contract.Assert(cmd.Lhss.Count == cmd.Rhss.Count); + for (int i = 0; i < cmd.Lhss.Count; i++) { + var lhs = cmd.Lhss[i]; + var rhs = cmd.Rhss[i]; + BigInteger? lo; + BigInteger? hi; + PartiallyEvaluate(rhs, e.N, out lo, out hi); + nn = UpdateOne(nn, lhs.DeepAssignedVariable, lo, hi); + } + return new E(nn); + } + + bool PartiallyEvaluate(Expr rhs, Node node, out BigInteger? lo, out BigInteger? hi) { + var pe = new PEVisitor(node); + pe.VisitExpr(rhs); + lo = pe.Lo; + hi = pe.Hi; + return lo != null || hi != null; + } + + class PEVisitor : ReadOnlyVisitor + { + public BigInteger? Lo; + public BigInteger? Hi; + + readonly BigInteger one = BigInteger.One; + + Node N; + public PEVisitor(Node n) { + N = n; + } + + // Override visitors for all expressions that can return a boolean, integer, or real result + + public override Expr VisitExpr(Expr node) { + Lo = Hi = null; + return base.VisitExpr(node); + } + public override Expr VisitLiteralExpr(LiteralExpr node) { + if (node.Val is BigNum) { + var n = ((BigNum)node.Val).ToBigInteger; + Lo = n; + Hi = n + 1; + } else if (node.Val is BigDec) { + BigInteger floor, ceiling; + ((BigDec)node.Val).FloorCeiling(out floor, out ceiling); + Lo = floor; + Hi = ceiling; + } else if (node.Val is bool) { + if ((bool)node.Val) { + // true + Lo = one; + Hi = null; + } else { + // false + Lo = null; + Hi = one; + } + } + return node; + } + public override Expr VisitIdentifierExpr(IdentifierExpr node) { + if (node.Type.IsBool || node.Type.IsInt || node.Type.IsReal) { + Node.GetBounds(N, node.Decl, out Lo, out Hi); + } + return node; + } + public override Expr VisitNAryExpr(NAryExpr node) { + if (node.Fun is UnaryOperator) { + var op = (UnaryOperator)node.Fun; + Contract.Assert(node.Args.Count == 1); + if (op.Op == UnaryOperator.Opcode.Neg) { + BigInteger? lo, hi; + VisitExpr(node.Args[0]); + lo = Lo; hi = Hi; + if (hi != null) { + Lo = node.Type.IsReal ? -hi : 1 - hi; + } + if (lo != null) { + Hi = node.Type.IsReal ? -lo : 1 - lo; + } + } + else if (op.Op == UnaryOperator.Opcode.Not) { + VisitExpr(node.Args[0]); + Contract.Assert((Lo == null && Hi == null) || + (Lo == null && (BigInteger)Hi == 1) || + (Hi == null && (BigInteger)Lo == 1)); + var tmp = Lo; + Lo = Hi; + Hi = tmp; + } + } else if (node.Fun is BinaryOperator) { + var op = (BinaryOperator)node.Fun; + Contract.Assert(node.Args.Count == 2); + BigInteger? lo0, hi0, lo1, hi1; + VisitExpr(node.Args[0]); + lo0 = Lo; hi0 = Hi; + VisitExpr(node.Args[1]); + lo1 = Lo; hi1 = Hi; + Lo = Hi = null; + var isReal = node.Args[0].Type.IsReal; + switch (op.Op) { + case BinaryOperator.Opcode.And: + if (hi0 != null || hi1 != null) { + // one operand is definitely false, thus so is the result + Lo = null; Hi = one; + } else if (lo0 != null && lo1 != null) { + // both operands are definitely true, thus so is the result + Lo = one; Hi = null; + } + break; + case BinaryOperator.Opcode.Or: + if (lo0 != null || lo1 != null) { + // one operand is definitely true, thus so is the result + Lo = one; Hi = null; + } else if (hi0 != null && hi1 != null) { + // both operands are definitely false, thus so is the result + Lo = null; Hi = one; + } + break; + case BinaryOperator.Opcode.Imp: + if (hi0 != null || lo1 != null) { + // either arg0 false or arg1 is true, so the result is true + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null) { + // arg0 is true and arg1 is false, so the result is false + Lo = null; Hi = one; + } + break; + case BinaryOperator.Opcode.Iff: + if (lo0 != null && lo1 != null) { + Lo = one; Hi = null; + } else if (hi0 != null && hi1 != null) { + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null) { + Lo = null; Hi = one; + } else if (hi0 != null && lo1 != null) { + Lo = null; Hi = one; + } + if (op.Op == BinaryOperator.Opcode.Neq) { + var tmp = Lo; Lo = Hi; Hi = tmp; + } + break; + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Neq: + if (node.Args[0].Type.IsBool) { + goto case BinaryOperator.Opcode.Iff; + } + // For Eq: + // If the (lo0,hi0) and (lo1,hi1) ranges do not overlap, the answer is false. + // If both ranges are the same unit range, then the answer is true. + if (hi0 != null && lo1 != null && (isReal ? hi0 < lo1 : hi0 <= lo1)) { + // no overlap + Lo = null; Hi = one; + } else if (lo0 != null && hi1 != null && (isReal ? hi1 < lo0 : hi1 <= lo0)) { + Lo = null; Hi = one; + // no overlaop + } else if (lo0 != null && hi0 != null && lo1 != null && hi1 != null && + lo0 == lo1 && hi0 == hi1 && // ranges are the same + (isReal ? lo0 == hi0 : lo0 + 1 == hi0)) { // unit range + // both ranges are the same unit range + Lo = one; Hi = null; + } + if (op.Op == BinaryOperator.Opcode.Neq) { + var tmp = Lo; Lo = Hi; Hi = tmp; + } + break; + case BinaryOperator.Opcode.Le: + if (isReal) { + // If hi0 <= lo1, then the answer is true. + // If hi1 < lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 <= lo1) { + Lo = one; Hi = null; + } else if (hi1 != null && lo0 != null && hi1 < lo0) { + Lo = null; Hi = one; + } + } else { + // If hi0 - 1 <= lo1, then the answer is true. + // If hi1 <= lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 - 1 <= lo1) { + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null && hi1 <= lo0) { + Lo = null; Hi = one; + } + } + break; + case BinaryOperator.Opcode.Lt: + if (isReal) { + // If hi0 < lo1, then the answer is true. + // If hi1 <= lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 < lo1) { + Lo = one; Hi = null; + } else if (hi1 != null && lo0 != null && hi1 <= lo0) { + Lo = null; Hi = one; + } + } else { + // If hi0 <= lo1, then the answer is true. + // If hi1 - 1 <= lo0, then the answer is false. + if (hi0 != null && lo1 != null && hi0 <= lo1) { + Lo = one; Hi = null; + } else if (lo0 != null && hi1 != null && hi1 - 1 <= lo0) { + Lo = null; Hi = one; + } + } + break; + case BinaryOperator.Opcode.Gt: + // swap the operands and then continue as Lt + { + var tmp = lo0; lo0 = lo1; lo1 = tmp; + tmp = hi0; hi0 = hi1; hi1 = tmp; + } + goto case BinaryOperator.Opcode.Lt; + case BinaryOperator.Opcode.Ge: + // swap the operands and then continue as Le + { + var tmp = lo0; lo0 = lo1; lo1 = tmp; + tmp = hi0; hi0 = hi1; hi1 = tmp; + } + goto case BinaryOperator.Opcode.Le; + case BinaryOperator.Opcode.Add: + if (lo0 != null && lo1 != null) { + Lo = lo0 + lo1; + } + if (hi0 != null && hi1 != null) { + Hi = isReal ? hi0 + hi1 : hi0 + hi1 - 1; + } + break; + case BinaryOperator.Opcode.Sub: + if (lo0 != null && hi1 != null) { + Lo = isReal ? lo0 - hi1 : lo0 - hi1 + 1; + } + if (hi0 != null && lo1 != null) { + Hi = hi0 - lo1; + } + break; + case BinaryOperator.Opcode.Mul: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null) { + if (0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = lo0 * lo1; + Hi = hi0 == null || hi1 == null ? null : isReal ? hi0 * hi1 : (hi0 - 1) * (hi1 - 1) + 1; + } else if ((BigInteger)lo0 < 0 && (BigInteger)lo1 < 0) { + Lo = null; // approximation + Hi = isReal ? lo0 * lo1 : lo0 * lo1 + 1; + } + } + break; + case BinaryOperator.Opcode.Div: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = BigInteger.Zero; + Hi = hi0; + } + break; + case BinaryOperator.Opcode.Mod: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = BigInteger.Zero; + Hi = hi1; + } + break; + case BinaryOperator.Opcode.RealDiv: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = BigInteger.Zero; + Hi = 1 <= (BigInteger)lo1 ? hi0 : null; + } + break; + case BinaryOperator.Opcode.Pow: + // this uses an incomplete approximation that could be tightened up + if (lo0 != null && lo1 != null && 0 <= (BigInteger)lo0 && 0 <= (BigInteger)lo1) { + Lo = 1 <= (BigInteger)lo1 ? BigInteger.One : BigInteger.Zero; + Hi = hi1; + } + break; + default: + break; + } + } else if (node.Fun is IfThenElse) { + var op = (IfThenElse)node.Fun; + Contract.Assert(node.Args.Count == 3); + BigInteger? guardLo, guardHi, lo0, hi0, lo1, hi1; + VisitExpr(node.Args[0]); + guardLo = Lo; guardHi = Hi; + VisitExpr(node.Args[1]); + lo0 = Lo; hi0 = Hi; + VisitExpr(node.Args[2]); + lo1 = Lo; hi1 = Hi; + Contract.Assert(guardLo == null || guardHi == null); // this is a consequence of the guard being boolean + if (guardLo != null) { + // guard is always true + Lo = lo0; Hi = hi0; + } else if (guardHi != null) { + // guard is always false + Lo = lo1; Hi = hi1; + } else { + // we don't know which branch will be taken, so join the information from the two branches + Lo = Node.Min(lo0, lo1, false); + Hi = Node.Max(hi0, hi1, false); + } + } else if (node.Fun is FunctionCall) { + var call = (FunctionCall)node.Fun; + // See if this is an identity function, which we do by checking: that the function has + // exactly one argument and the function has been marked by the user with the attribute {:identity} + bool claimsToBeIdentity = false; + if (call.ArgumentCount == 1 && call.Func.CheckBooleanAttribute("identity", ref claimsToBeIdentity) && claimsToBeIdentity && node.Args[0].Type.Equals(node.Type)) { + VisitExpr(node.Args[0]); + } + } + return node; + } + public override BinderExpr VisitBinderExpr(BinderExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitOldExpr(OldExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitCodeExpr(CodeExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitBvConcatExpr(BvConcatExpr node) { + // don't recurse on subexpression + return node; + } + public override Expr VisitBvExtractExpr(BvExtractExpr node) { + // don't recurse on subexpression + return node; + } + } + + public override Element Eliminate(Element element, Variable v) { + if (element is E_Bottom) { + return element; + } + var e = (E)element; + var nn = UpdateOne(e.N, v, null, null); + if (nn == e.N) { + return element; + } else { + return new E(nn); + } + } + + Node UpdateOne(Node nn, Variable v, BigInteger? lo, BigInteger? hi) { + var orig = nn; + Node head = null; + Node prev = null; + var foundV = false; + for (; nn != null && !Node.StrictlyBefore(v, nn.V); nn = nn.Next) { + if (nn.V == v) { + foundV = true; + nn = nn.Next; + break; // we found the place where the new node goes + } else { + var n = new Node(nn.V, nn.Lo, nn.Hi); // copy this Node + if (head == null) { + head = n; + } else { + prev.Next = n; + } + prev = n; + } + } + Node rest; + if (lo == null && hi == null) { + // eliminate all information about "v" + if (!foundV) { + return orig; + } + rest = nn; + } else { + rest = new Node(v, lo, hi); + rest.Next = nn; + } + if (head == null) { + head = rest; + } else { + prev.Next = rest; + } + return head; + } + + /// + /// Return a resolved/type-checked expression that represents the conjunction of a and b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplAnd(Expr a, Expr b) { + if (a == Expr.True) { + return b; + } else if (b == Expr.True) { + return a; + } else { + var nary = Expr.Binary(BinaryOperator.Opcode.And, a, b); + nary.Type = Type.Bool; + nary.TypeParameters = SimpleTypeParamInstantiation.EMPTY; + return nary; + } + } + + /// + /// Return a resolved/type-checked expression that represents a EQUALS b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplEq(Expr a, Expr b) { + var e = Expr.Eq(a, b); + e.Type = Type.Bool; + return e; + } + + /// + /// Return a resolved/type-checked expression that represents a LESS-EQUAL b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplLe(Expr a, Expr b) { + var e = Expr.Le(a, b); + e.Type = Type.Bool; + return e; + } + /// + /// Return a resolved/type-checked expression that represents a LESS b. + /// Requires a and b to be resolved and type checked already. + /// + public static Expr BplLt(Expr a, Expr b) { + var e = Expr.Lt(a, b); + e.Type = Type.Bool; + return e; + } + } + + public class ThresholdFinder : ReadOnlyVisitor + { + readonly Implementation Impl; + public ThresholdFinder(Implementation impl) { + Contract.Requires(impl != null); + Impl = impl; + } + HashSet downs = new HashSet(); + HashSet ups = new HashSet(); + public void Find(out List downThresholds, out List upThresholds) { + // always include -1, 0, 1 as down-thresholds + downs.Clear(); + downs.Add(-1); + downs.Add(0); + downs.Add(1); + // always include 0 and 1 as up-thresholds + ups.Clear(); + ups.Add(0); + ups.Add(1); + + foreach (Requires p in Impl.Proc.Requires) { + Visit(p.Condition); + } + foreach (Ensures p in Impl.Proc.Ensures) { + Visit(p.Condition); + } + foreach (var b in Impl.Blocks) { + foreach (Cmd c in b.Cmds) { + Visit(c); + } + } + + // convert the HashSets to sorted Lists and return + downThresholds = new List(); + foreach (var i in downs) { + downThresholds.Add(i); + } + downThresholds.Sort(); + upThresholds = new List(); + foreach (var i in ups) { + upThresholds.Add(i); + } + upThresholds.Sort(); + } + + public override Expr VisitNAryExpr(NAryExpr node) { + if (node.Fun is BinaryOperator) { + var op = (BinaryOperator)node.Fun; + Contract.Assert(node.Args.Count == 2); + var arg0 = node.Args[0]; + var arg1 = node.Args[1]; + var offset = arg0.Type.IsReal ? 0 : 1; + BigInteger? k; + switch (op.Op) { + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Neq: + k = AsIntLiteral(arg0); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i - 1); + downs.Add(i); + ups.Add(i + 1); + ups.Add(i + 2); + } + k = AsIntLiteral(arg1); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i - 1); + downs.Add(i); + ups.Add(i + 1); + ups.Add(i + 2); + } + break; + case BinaryOperator.Opcode.Le: + k = AsIntLiteral(arg0); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i - 1); + downs.Add(i); + } + k = AsIntLiteral(arg1); + if (k != null) { + var i = (BigInteger)k; + ups.Add(i + offset); + ups.Add(i + 1 + offset); + } + break; + case BinaryOperator.Opcode.Lt: + k = AsIntLiteral(arg0); + if (k != null) { + var i = (BigInteger)k; + downs.Add(i ); + downs.Add(i + 1); + } + k = AsIntLiteral(arg1); + if (k != null) { + var i = (BigInteger)k; + ups.Add(i - 1 + offset); + ups.Add(i + offset); + } + break; + case BinaryOperator.Opcode.Ge: + { var tmp = arg0; arg0 = arg1; arg1 = tmp; } + goto case BinaryOperator.Opcode.Le; + case BinaryOperator.Opcode.Gt: + { var tmp = arg0; arg0 = arg1; arg1 = tmp; } + goto case BinaryOperator.Opcode.Lt; + default: + break; + } + } + return base.VisitNAryExpr(node); + } + + BigInteger? AsIntLiteral(Expr e) { + var lit = e as LiteralExpr; + if (lit != null && lit.isBigNum) { + BigNum bn = lit.asBigNum; + return bn.ToBigInteger; + } + return null; + } + } + +} diff --git a/Source/AbsInt/NativeLattice.cs b/Source/AbsInt/NativeLattice.cs index 30014643..d1ae215a 100644 --- a/Source/AbsInt/NativeLattice.cs +++ b/Source/AbsInt/NativeLattice.cs @@ -1,335 +1,335 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using Microsoft.Boogie; - -namespace Microsoft.Boogie.AbstractInterpretation -{ - /// - /// Specifies the operations (e.g., join) on a mathematical lattice that depend - /// only on the elements of the lattice. - /// - public abstract class NativeLattice - { - /// - /// An element of the lattice. This class should be derived from in any - /// implementation of MathematicalLattice. - /// - public abstract class Element - { - public abstract Expr ToExpr(); - } - - public abstract Element Top { get; } - public abstract Element Bottom { get; } - - public abstract bool IsTop(Element element); - public abstract bool IsBottom(Element element); - - /// - /// Is 'a' better (or equal) information than 'b'? That is, is 'a' below 'b' in the lattice? - /// - public abstract bool Below(Element a, Element b); - - public abstract Element Meet(Element a, Element b); - public abstract Element Join(Element a, Element b); - public abstract Element Widen(Element a, Element b); - - public abstract Element Constrain(Element element, Expr expr); - public abstract Element Update(Element element, AssignCmd cmd); // requiers 'cmd' to be a simple (possibly parallel) assignment command - public abstract Element Eliminate(Element element, Variable v); - - /// - /// Specialize the lattice to implementation "impl", if non-null. - /// If "impl" is null, remove specialization. - /// - public virtual void Specialize(Implementation impl) { - } - - public virtual void Validate() { - Contract.Assert(IsTop(Top)); - Contract.Assert(IsBottom(Bottom)); - Contract.Assert(!IsBottom(Top)); - Contract.Assert(!IsTop(Bottom)); - - Contract.Assert(Below(Top, Top)); - Contract.Assert(Below(Bottom, Top)); - Contract.Assert(Below(Bottom, Bottom)); - - Contract.Assert(IsTop(Join(Top, Top))); - Contract.Assert(IsBottom(Join(Bottom, Bottom))); - } - } - - public class NativeAbstractInterpretation - { - public static void RunAbstractInterpretation(Program program) { - Contract.Requires(program != null); - - if (!CommandLineOptions.Clo.UseAbstractInterpretation) { - return; - } - Helpers.ExtraTraceInformation("Starting abstract interpretation"); - - DateTime start = new DateTime(); // to please compiler's definite assignment rules - if (CommandLineOptions.Clo.Trace) { - Console.WriteLine(); - Console.WriteLine("Running abstract interpretation..."); - start = DateTime.UtcNow; - } - - WidenPoints.Compute(program); - - NativeLattice lattice = null; - if (CommandLineOptions.Clo.Ai.J_Trivial) { - lattice = new TrivialDomain(); - } else if (CommandLineOptions.Clo.Ai.J_Intervals) { - lattice = new NativeIntervallDomain(); - } - - if (lattice != null) { - Dictionary procedureImplementations = ComputeProcImplMap(program); - ComputeProgramInvariants(program, procedureImplementations, lattice); - if (CommandLineOptions.Clo.Ai.DebugStatistics) { - Console.Error.WriteLine(lattice); - } - } - - if (CommandLineOptions.Clo.Trace) { - DateTime end = DateTime.UtcNow; - TimeSpan elapsed = end - start; - Console.WriteLine(" [{0} s]", elapsed.TotalSeconds); - Console.Out.Flush(); - } - } - - private static Dictionary ComputeProcImplMap(Program program) { - Contract.Requires(program != null); - // Since implementations call procedures (impl. signatures) - // rather than directly calling other implementations, we first - // need to compute which implementations implement which - // procedures and remember which implementations call which - // procedures. - - return program - .Implementations - .GroupBy(i => i.Proc).Select(g => g.ToArray()).ToDictionary(a => a[0].Proc); - } - - /// - /// Compute and apply the invariants for the program using the underlying abstract domain. - /// - public static void ComputeProgramInvariants(Program program, Dictionary procedureImplementations, NativeLattice lattice) { - Contract.Requires(program != null); - Contract.Requires(procedureImplementations != null); - Contract.Requires(lattice != null); - - // Gather all the axioms to create the initial lattice element - // Differently stated, it is the \alpha from axioms (i.e. first order formulae) to the underlyng abstract domain - var initialElement = lattice.Top; - Contract.Assert(initialElement != null); - foreach (var ax in program.Axioms) { - initialElement = lattice.Constrain(initialElement, ax.Expr); - } - - // analyze each procedure - foreach (var proc in program.Procedures) { - if (procedureImplementations.ContainsKey(proc)) { - // analyze each implementation of the procedure - foreach (var impl in procedureImplementations[proc]) { - // add the precondition to the axioms - Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap()); - var start = initialElement; - foreach (Requires pre in proc.Requires) { - Expr e = Substituter.Apply(formalProcImplSubst, pre.Condition); - start = lattice.Constrain(start, e); - } - - lattice.Specialize(impl); - Analyze(impl, lattice, start); - lattice.Specialize(null); - } - } - } - } - - public static void Analyze(Implementation impl, NativeLattice lattice, NativeLattice.Element start) { - // We need to keep track of some information for each(some) block(s). To do that efficiently, - // we number the implementation's blocks sequentially, and then we can use arrays to store - // the additional information. - var pre = new NativeLattice.Element[impl.Blocks.Count]; // set to null if we never compute a join/widen at this block - var post = CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere ? new NativeLattice.Element[impl.Blocks.Count] : null; - var iterations = new int[impl.Blocks.Count]; - var bottom = lattice.Bottom; - int n = 0; - foreach (var block in impl.Blocks) { - block.aiId = n; - // Note: The forward analysis below will store lattice elements in pre[n] if pre[n] is non-null. - // Thus, the assignment "pre[n] = bottom;" below must be done under the following condition: - // n == 0 || block.widenBlock - // One possible strategy would be to do it only under that condition. Alternatively, - // one could do the assignment under the following condition: - // n == 0 || block.widenBlock || block.Predecessors.Length != 1 - // (which would require first setting the Predecessors field). In any case, if - // CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere - // then all pre[n] should be set. - pre[n] = bottom; - n++; - } - Contract.Assert(n == impl.Blocks.Count); - - var workItems = new Queue>(); - workItems.Enqueue(new Tuple(impl.Blocks[0], start)); - //ComputeBlockInvariantsNative(impl, ); - // compute a fixpoint here - while (workItems.Count > 0) { - var workItem = workItems.Dequeue(); - var b = workItem.Item1; - var id = b.aiId; - var e = workItem.Item2; - if (pre[id] == null) { - // no pre information stored here, so just go ahead through the block - } else if (lattice.Below(e, pre[id])) { - // no change - continue; - } else if (b.widenBlock && CommandLineOptions.Clo.StepsBeforeWidening <= iterations[id]) { - e = lattice.Widen(pre[id], e); - pre[id] = e; - iterations[id]++; - } else { - e = lattice.Join(pre[id], e); - pre[id] = e; - iterations[id]++; - } - - // propagate'e' through b.Cmds - foreach (Cmd cmd in b.Cmds) { - e = Step(lattice, cmd, e); - } - - if (post != null && pre[id] != null) { - post[id] = e; - } - - var g = b.TransferCmd as GotoCmd; - if (g != null) { // if g==null, it's a pity we didn't pay attention to that earlier, because then we could have skipped analyzing the code in this block - foreach (Block succ in g.labelTargets) { - workItems.Enqueue(new Tuple(succ, e)); - } - } - } - - Instrument(impl, pre, post); - } - - static void Instrument(Implementation impl, NativeLattice.Element[] pre, NativeLattice.Element[] post) { - Contract.Requires(impl != null); - Contract.Requires(pre != null); - - foreach (var b in impl.Blocks) { - var element = pre[b.aiId]; - if (element != null && (b.widenBlock || CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere)) { - List newCommands = new List(); - Expr inv = element.ToExpr(); - PredicateCmd cmd; - var kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); - if (CommandLineOptions.Clo.InstrumentWithAsserts) { - cmd = new AssertCmd(Token.NoToken, inv, kv); - } else { - cmd = new AssumeCmd(Token.NoToken, inv, kv); - } - newCommands.Add(cmd); - newCommands.AddRange(b.Cmds); - if (post != null && post[b.aiId] != null) { - inv = post[b.aiId].ToExpr(); - kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); - if (CommandLineOptions.Clo.InstrumentWithAsserts) { - cmd = new AssertCmd(Token.NoToken, inv, kv); - } else { - cmd = new AssumeCmd(Token.NoToken, inv, kv); - } - newCommands.Add(cmd); - } - b.Cmds = newCommands; // destructively replace the commands of the block - } - } - } - - /// - /// The abstract transition relation. - /// 'cmd' is allowed to be a StateCmd. - /// - static NativeLattice.Element Step(NativeLattice lattice, Cmd cmd, NativeLattice.Element elmt) { - Contract.Requires(lattice != null); - Contract.Requires(cmd != null); - Contract.Requires(elmt != null); - Contract.Ensures(Contract.Result() != null); - - if (cmd is AssignCmd) { // parallel assignment - var c = (AssignCmd)cmd; - elmt = lattice.Update(elmt, c.AsSimpleAssignCmd); - } else if (cmd is HavocCmd) { - var c = (HavocCmd)cmd; - foreach (IdentifierExpr id in c.Vars) { - Contract.Assert(id != null); - elmt = lattice.Eliminate(elmt, id.Decl); - } - } else if (cmd is PredicateCmd) { - var c = (PredicateCmd)cmd; - var conjuncts = new List(); - foreach (var ee in Conjuncts(c.Expr)) { - Contract.Assert(ee != null); - elmt = lattice.Constrain(elmt, ee); - } - } else if (cmd is StateCmd) { - var c = (StateCmd)cmd; - // Iterate the abstract transition on all the commands in the desugaring of the call - foreach (Cmd callDesug in c.Cmds) { - Contract.Assert(callDesug != null); - elmt = Step(lattice, callDesug, elmt); - } - // Project out the local variables of the StateCmd - foreach (Variable local in c.Locals) { - Contract.Assert(local != null); - elmt = lattice.Eliminate(elmt, local); - } - } else if (cmd is SugaredCmd) { - var c = (SugaredCmd)cmd; - elmt = Step(lattice, c.Desugaring, elmt); - } else if (cmd is CommentCmd) { - // skip - } else { - Contract.Assert(false); // unknown command - } - return elmt; - } - - /// - /// Yields the conjuncts of 'expr'. - /// - public static IEnumerable Conjuncts(Expr expr) { - Contract.Requires(expr != null); - - var e = expr as NAryExpr; - if (e != null && e.Fun.FunctionName == "&&") { // if it is a conjunction - foreach (Expr ee in e.Args) { - Contract.Assert(ee != null); - foreach (var c in Conjuncts(ee)) { - yield return c; - } - } - } else { - yield return expr; - } - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using Microsoft.Boogie; + +namespace Microsoft.Boogie.AbstractInterpretation +{ + /// + /// Specifies the operations (e.g., join) on a mathematical lattice that depend + /// only on the elements of the lattice. + /// + public abstract class NativeLattice + { + /// + /// An element of the lattice. This class should be derived from in any + /// implementation of MathematicalLattice. + /// + public abstract class Element + { + public abstract Expr ToExpr(); + } + + public abstract Element Top { get; } + public abstract Element Bottom { get; } + + public abstract bool IsTop(Element element); + public abstract bool IsBottom(Element element); + + /// + /// Is 'a' better (or equal) information than 'b'? That is, is 'a' below 'b' in the lattice? + /// + public abstract bool Below(Element a, Element b); + + public abstract Element Meet(Element a, Element b); + public abstract Element Join(Element a, Element b); + public abstract Element Widen(Element a, Element b); + + public abstract Element Constrain(Element element, Expr expr); + public abstract Element Update(Element element, AssignCmd cmd); // requiers 'cmd' to be a simple (possibly parallel) assignment command + public abstract Element Eliminate(Element element, Variable v); + + /// + /// Specialize the lattice to implementation "impl", if non-null. + /// If "impl" is null, remove specialization. + /// + public virtual void Specialize(Implementation impl) { + } + + public virtual void Validate() { + Contract.Assert(IsTop(Top)); + Contract.Assert(IsBottom(Bottom)); + Contract.Assert(!IsBottom(Top)); + Contract.Assert(!IsTop(Bottom)); + + Contract.Assert(Below(Top, Top)); + Contract.Assert(Below(Bottom, Top)); + Contract.Assert(Below(Bottom, Bottom)); + + Contract.Assert(IsTop(Join(Top, Top))); + Contract.Assert(IsBottom(Join(Bottom, Bottom))); + } + } + + public class NativeAbstractInterpretation + { + public static void RunAbstractInterpretation(Program program) { + Contract.Requires(program != null); + + if (!CommandLineOptions.Clo.UseAbstractInterpretation) { + return; + } + Helpers.ExtraTraceInformation("Starting abstract interpretation"); + + DateTime start = new DateTime(); // to please compiler's definite assignment rules + if (CommandLineOptions.Clo.Trace) { + Console.WriteLine(); + Console.WriteLine("Running abstract interpretation..."); + start = DateTime.UtcNow; + } + + WidenPoints.Compute(program); + + NativeLattice lattice = null; + if (CommandLineOptions.Clo.Ai.J_Trivial) { + lattice = new TrivialDomain(); + } else if (CommandLineOptions.Clo.Ai.J_Intervals) { + lattice = new NativeIntervallDomain(); + } + + if (lattice != null) { + Dictionary procedureImplementations = ComputeProcImplMap(program); + ComputeProgramInvariants(program, procedureImplementations, lattice); + if (CommandLineOptions.Clo.Ai.DebugStatistics) { + Console.Error.WriteLine(lattice); + } + } + + if (CommandLineOptions.Clo.Trace) { + DateTime end = DateTime.UtcNow; + TimeSpan elapsed = end - start; + Console.WriteLine(" [{0} s]", elapsed.TotalSeconds); + Console.Out.Flush(); + } + } + + private static Dictionary ComputeProcImplMap(Program program) { + Contract.Requires(program != null); + // Since implementations call procedures (impl. signatures) + // rather than directly calling other implementations, we first + // need to compute which implementations implement which + // procedures and remember which implementations call which + // procedures. + + return program + .Implementations + .GroupBy(i => i.Proc).Select(g => g.ToArray()).ToDictionary(a => a[0].Proc); + } + + /// + /// Compute and apply the invariants for the program using the underlying abstract domain. + /// + public static void ComputeProgramInvariants(Program program, Dictionary procedureImplementations, NativeLattice lattice) { + Contract.Requires(program != null); + Contract.Requires(procedureImplementations != null); + Contract.Requires(lattice != null); + + // Gather all the axioms to create the initial lattice element + // Differently stated, it is the \alpha from axioms (i.e. first order formulae) to the underlyng abstract domain + var initialElement = lattice.Top; + Contract.Assert(initialElement != null); + foreach (var ax in program.Axioms) { + initialElement = lattice.Constrain(initialElement, ax.Expr); + } + + // analyze each procedure + foreach (var proc in program.Procedures) { + if (procedureImplementations.ContainsKey(proc)) { + // analyze each implementation of the procedure + foreach (var impl in procedureImplementations[proc]) { + // add the precondition to the axioms + Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap()); + var start = initialElement; + foreach (Requires pre in proc.Requires) { + Expr e = Substituter.Apply(formalProcImplSubst, pre.Condition); + start = lattice.Constrain(start, e); + } + + lattice.Specialize(impl); + Analyze(impl, lattice, start); + lattice.Specialize(null); + } + } + } + } + + public static void Analyze(Implementation impl, NativeLattice lattice, NativeLattice.Element start) { + // We need to keep track of some information for each(some) block(s). To do that efficiently, + // we number the implementation's blocks sequentially, and then we can use arrays to store + // the additional information. + var pre = new NativeLattice.Element[impl.Blocks.Count]; // set to null if we never compute a join/widen at this block + var post = CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere ? new NativeLattice.Element[impl.Blocks.Count] : null; + var iterations = new int[impl.Blocks.Count]; + var bottom = lattice.Bottom; + int n = 0; + foreach (var block in impl.Blocks) { + block.aiId = n; + // Note: The forward analysis below will store lattice elements in pre[n] if pre[n] is non-null. + // Thus, the assignment "pre[n] = bottom;" below must be done under the following condition: + // n == 0 || block.widenBlock + // One possible strategy would be to do it only under that condition. Alternatively, + // one could do the assignment under the following condition: + // n == 0 || block.widenBlock || block.Predecessors.Length != 1 + // (which would require first setting the Predecessors field). In any case, if + // CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere + // then all pre[n] should be set. + pre[n] = bottom; + n++; + } + Contract.Assert(n == impl.Blocks.Count); + + var workItems = new Queue>(); + workItems.Enqueue(new Tuple(impl.Blocks[0], start)); + //ComputeBlockInvariantsNative(impl, ); + // compute a fixpoint here + while (workItems.Count > 0) { + var workItem = workItems.Dequeue(); + var b = workItem.Item1; + var id = b.aiId; + var e = workItem.Item2; + if (pre[id] == null) { + // no pre information stored here, so just go ahead through the block + } else if (lattice.Below(e, pre[id])) { + // no change + continue; + } else if (b.widenBlock && CommandLineOptions.Clo.StepsBeforeWidening <= iterations[id]) { + e = lattice.Widen(pre[id], e); + pre[id] = e; + iterations[id]++; + } else { + e = lattice.Join(pre[id], e); + pre[id] = e; + iterations[id]++; + } + + // propagate'e' through b.Cmds + foreach (Cmd cmd in b.Cmds) { + e = Step(lattice, cmd, e); + } + + if (post != null && pre[id] != null) { + post[id] = e; + } + + var g = b.TransferCmd as GotoCmd; + if (g != null) { // if g==null, it's a pity we didn't pay attention to that earlier, because then we could have skipped analyzing the code in this block + foreach (Block succ in g.labelTargets) { + workItems.Enqueue(new Tuple(succ, e)); + } + } + } + + Instrument(impl, pre, post); + } + + static void Instrument(Implementation impl, NativeLattice.Element[] pre, NativeLattice.Element[] post) { + Contract.Requires(impl != null); + Contract.Requires(pre != null); + + foreach (var b in impl.Blocks) { + var element = pre[b.aiId]; + if (element != null && (b.widenBlock || CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere)) { + List newCommands = new List(); + Expr inv = element.ToExpr(); + PredicateCmd cmd; + var kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); + if (CommandLineOptions.Clo.InstrumentWithAsserts) { + cmd = new AssertCmd(Token.NoToken, inv, kv); + } else { + cmd = new AssumeCmd(Token.NoToken, inv, kv); + } + newCommands.Add(cmd); + newCommands.AddRange(b.Cmds); + if (post != null && post[b.aiId] != null) { + inv = post[b.aiId].ToExpr(); + kv = new QKeyValue(Token.NoToken, "inferred", new List(), null); + if (CommandLineOptions.Clo.InstrumentWithAsserts) { + cmd = new AssertCmd(Token.NoToken, inv, kv); + } else { + cmd = new AssumeCmd(Token.NoToken, inv, kv); + } + newCommands.Add(cmd); + } + b.Cmds = newCommands; // destructively replace the commands of the block + } + } + } + + /// + /// The abstract transition relation. + /// 'cmd' is allowed to be a StateCmd. + /// + static NativeLattice.Element Step(NativeLattice lattice, Cmd cmd, NativeLattice.Element elmt) { + Contract.Requires(lattice != null); + Contract.Requires(cmd != null); + Contract.Requires(elmt != null); + Contract.Ensures(Contract.Result() != null); + + if (cmd is AssignCmd) { // parallel assignment + var c = (AssignCmd)cmd; + elmt = lattice.Update(elmt, c.AsSimpleAssignCmd); + } else if (cmd is HavocCmd) { + var c = (HavocCmd)cmd; + foreach (IdentifierExpr id in c.Vars) { + Contract.Assert(id != null); + elmt = lattice.Eliminate(elmt, id.Decl); + } + } else if (cmd is PredicateCmd) { + var c = (PredicateCmd)cmd; + var conjuncts = new List(); + foreach (var ee in Conjuncts(c.Expr)) { + Contract.Assert(ee != null); + elmt = lattice.Constrain(elmt, ee); + } + } else if (cmd is StateCmd) { + var c = (StateCmd)cmd; + // Iterate the abstract transition on all the commands in the desugaring of the call + foreach (Cmd callDesug in c.Cmds) { + Contract.Assert(callDesug != null); + elmt = Step(lattice, callDesug, elmt); + } + // Project out the local variables of the StateCmd + foreach (Variable local in c.Locals) { + Contract.Assert(local != null); + elmt = lattice.Eliminate(elmt, local); + } + } else if (cmd is SugaredCmd) { + var c = (SugaredCmd)cmd; + elmt = Step(lattice, c.Desugaring, elmt); + } else if (cmd is CommentCmd) { + // skip + } else { + Contract.Assert(false); // unknown command + } + return elmt; + } + + /// + /// Yields the conjuncts of 'expr'. + /// + public static IEnumerable Conjuncts(Expr expr) { + Contract.Requires(expr != null); + + var e = expr as NAryExpr; + if (e != null && e.Fun.FunctionName == "&&") { // if it is a conjunction + foreach (Expr ee in e.Args) { + Contract.Assert(ee != null); + foreach (var c in Conjuncts(ee)) { + yield return c; + } + } + } else { + yield return expr; + } + } + + } +} diff --git a/Source/AbsInt/Traverse.cs b/Source/AbsInt/Traverse.cs index 184a4071..92377e56 100644 --- a/Source/AbsInt/Traverse.cs +++ b/Source/AbsInt/Traverse.cs @@ -1,169 +1,169 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.Boogie { - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - - - /// - /// This class provides the functionality of traversing a program to determine which - /// blocks are blocks where the widening operator may need to be applied. Assumes - /// all 'currentlyTraversed' bits to be initially false, and leaves them that way in - /// the end. Assumes the 'widenBlock' bits are initially false, and sets them - /// appropriately. - /// - public class WidenPoints { - /// - /// Compute the widen points of a program - /// - public static void Compute(Program program) { - Contract.Requires(program != null); - cce.BeginExpose(program); - - foreach (var impl in program.Implementations) { - if (impl.Blocks != null && impl.Blocks.Count > 0) { - Contract.Assume(cce.IsConsistent(impl)); - cce.BeginExpose(impl); - Block start = impl.Blocks[0]; - Contract.Assume(start != null); - Contract.Assume(cce.IsConsistent(start)); - Visit(start); - - // We reset the state... - foreach (Block b in impl.Blocks) { - cce.BeginExpose(b); - b.TraversingStatus = Block.VisitState.ToVisit; - cce.EndExpose(); - } - cce.EndExpose(); - } - } - cce.EndExpose(); - } - - static void Visit(Block b) { - Contract.Requires(b != null); - Contract.Assume(cce.IsExposable(b)); - if (b.TraversingStatus == Block.VisitState.BeingVisited) { - cce.BeginExpose(b); - // we got here through a back-edge - b.widenBlock = true; - cce.EndExpose(); - } else if (b.TraversingStatus == Block.VisitState.AlreadyVisited) { - // do nothing... we already saw this node - } else if (b.TransferCmd is GotoCmd) { - Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit); - - GotoCmd g = (GotoCmd)b.TransferCmd; - cce.BeginExpose(b); - - cce.BeginExpose(g); //PM: required for the subsequent expose (g.labelTargets) - b.TraversingStatus = Block.VisitState.BeingVisited; - - // labelTargets is made non-null by Resolve, which we assume - // has already called in a prior pass. - Contract.Assume(g.labelTargets != null); - cce.BeginExpose(g.labelTargets); - foreach (Block succ in g.labelTargets) - // invariant b.currentlyTraversed; - //PM: The following loop invariant will work once properties are axiomatized - //&& (g.labelNames != null && g.labelTargets != null ==> g.labelNames.Length == g.labelTargets.Length); - { - Contract.Assert(succ != null); - Visit(succ); - } - cce.EndExpose(); - - Contract.Assert(b.TraversingStatus == Block.VisitState.BeingVisited); - // System.Diagnostics.Debug.Assert(b.currentlyTraversed); - - b.TraversingStatus = Block.VisitState.AlreadyVisited; - - //PM: The folowing assumption is needed because we cannot prove that a simple field update - //PM: leaves the value of a property unchanged. - Contract.Assume(g.labelNames == null || g.labelNames.Count == g.labelTargets.Count); - cce.EndExpose(); - } else { - Contract.Assert(b.TransferCmd == null || b.TransferCmd is ReturnCmd); // It must be a returnCmd; - } - } - - static private Block rootBlock = null; // The root point we have to consider - - /// - /// Compute the blocks in the body loop. - /// Tt is the head of the loop. It must be a widen block - /// The blocks that are in the loop from block - /// - public static List ComputeLoopBodyFrom(Block block) { - Contract.Requires(block.widenBlock); - Contract.Requires(block != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - Contract.Assert(rootBlock == null); - rootBlock = block; - - List blocksInLoop = new List(); // We use a list just because .net does not define a set - List visitingPath = new List(); // The order is important, as we want paths - - blocksInLoop.Add(block); - - DoDFSVisit(block, visitingPath, blocksInLoop); - - visitingPath.Add(block); - - - rootBlock = null; // We reset the invariant - - return blocksInLoop; - } - - /// - /// Perform the Depth-first search of the so to find the loop - /// The block to visit - /// The path we are visiting so far - /// - private static void DoDFSVisit(Block block, List path, List blocksInPath) { - Contract.Requires(block != null); - Contract.Requires(cce.NonNullElements(path)); - Contract.Requires(cce.NonNullElements(path)); - #region case 1. We visit the root => We are done, "path" is a path inside the loop - if (block == rootBlock && path.Count > 1) { - blocksInPath.AddRange(path); // Add all the blocks in this path - } - - #endregion - #region case 2. We visit a node that ends with a return => "path" is not inside the loop - if (block.TransferCmd is ReturnCmd) { - return; - } - #endregion - #region case 3. We visit a node with successors => continue the exploration of its successors - { - Contract.Assert(block.TransferCmd is GotoCmd); - GotoCmd successors = (GotoCmd)block.TransferCmd; - Contract.Assert(successors != null); - - if (successors.labelTargets != null) - foreach (Block nextBlock in successors.labelTargets) { - Contract.Assert(nextBlock != null); - if (path.Contains(nextBlock)) // If the current path has already seen the block, just skip it - continue; - // Otherwise we perform the DFS visit - path.Add(nextBlock); - DoDFSVisit(nextBlock, path, blocksInPath); - - Contract.Assert(nextBlock == path[path.Count - 1]); - path.RemoveAt(path.Count - 1); - } - - } - - #endregion - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.Boogie { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + + /// + /// This class provides the functionality of traversing a program to determine which + /// blocks are blocks where the widening operator may need to be applied. Assumes + /// all 'currentlyTraversed' bits to be initially false, and leaves them that way in + /// the end. Assumes the 'widenBlock' bits are initially false, and sets them + /// appropriately. + /// + public class WidenPoints { + /// + /// Compute the widen points of a program + /// + public static void Compute(Program program) { + Contract.Requires(program != null); + cce.BeginExpose(program); + + foreach (var impl in program.Implementations) { + if (impl.Blocks != null && impl.Blocks.Count > 0) { + Contract.Assume(cce.IsConsistent(impl)); + cce.BeginExpose(impl); + Block start = impl.Blocks[0]; + Contract.Assume(start != null); + Contract.Assume(cce.IsConsistent(start)); + Visit(start); + + // We reset the state... + foreach (Block b in impl.Blocks) { + cce.BeginExpose(b); + b.TraversingStatus = Block.VisitState.ToVisit; + cce.EndExpose(); + } + cce.EndExpose(); + } + } + cce.EndExpose(); + } + + static void Visit(Block b) { + Contract.Requires(b != null); + Contract.Assume(cce.IsExposable(b)); + if (b.TraversingStatus == Block.VisitState.BeingVisited) { + cce.BeginExpose(b); + // we got here through a back-edge + b.widenBlock = true; + cce.EndExpose(); + } else if (b.TraversingStatus == Block.VisitState.AlreadyVisited) { + // do nothing... we already saw this node + } else if (b.TransferCmd is GotoCmd) { + Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit); + + GotoCmd g = (GotoCmd)b.TransferCmd; + cce.BeginExpose(b); + + cce.BeginExpose(g); //PM: required for the subsequent expose (g.labelTargets) + b.TraversingStatus = Block.VisitState.BeingVisited; + + // labelTargets is made non-null by Resolve, which we assume + // has already called in a prior pass. + Contract.Assume(g.labelTargets != null); + cce.BeginExpose(g.labelTargets); + foreach (Block succ in g.labelTargets) + // invariant b.currentlyTraversed; + //PM: The following loop invariant will work once properties are axiomatized + //&& (g.labelNames != null && g.labelTargets != null ==> g.labelNames.Length == g.labelTargets.Length); + { + Contract.Assert(succ != null); + Visit(succ); + } + cce.EndExpose(); + + Contract.Assert(b.TraversingStatus == Block.VisitState.BeingVisited); + // System.Diagnostics.Debug.Assert(b.currentlyTraversed); + + b.TraversingStatus = Block.VisitState.AlreadyVisited; + + //PM: The folowing assumption is needed because we cannot prove that a simple field update + //PM: leaves the value of a property unchanged. + Contract.Assume(g.labelNames == null || g.labelNames.Count == g.labelTargets.Count); + cce.EndExpose(); + } else { + Contract.Assert(b.TransferCmd == null || b.TransferCmd is ReturnCmd); // It must be a returnCmd; + } + } + + static private Block rootBlock = null; // The root point we have to consider + + /// + /// Compute the blocks in the body loop. + /// Tt is the head of the loop. It must be a widen block + /// The blocks that are in the loop from block + /// + public static List ComputeLoopBodyFrom(Block block) { + Contract.Requires(block.widenBlock); + Contract.Requires(block != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + + Contract.Assert(rootBlock == null); + rootBlock = block; + + List blocksInLoop = new List(); // We use a list just because .net does not define a set + List visitingPath = new List(); // The order is important, as we want paths + + blocksInLoop.Add(block); + + DoDFSVisit(block, visitingPath, blocksInLoop); + + visitingPath.Add(block); + + + rootBlock = null; // We reset the invariant + + return blocksInLoop; + } + + /// + /// Perform the Depth-first search of the so to find the loop + /// The block to visit + /// The path we are visiting so far + /// + private static void DoDFSVisit(Block block, List path, List blocksInPath) { + Contract.Requires(block != null); + Contract.Requires(cce.NonNullElements(path)); + Contract.Requires(cce.NonNullElements(path)); + #region case 1. We visit the root => We are done, "path" is a path inside the loop + if (block == rootBlock && path.Count > 1) { + blocksInPath.AddRange(path); // Add all the blocks in this path + } + + #endregion + #region case 2. We visit a node that ends with a return => "path" is not inside the loop + if (block.TransferCmd is ReturnCmd) { + return; + } + #endregion + #region case 3. We visit a node with successors => continue the exploration of its successors + { + Contract.Assert(block.TransferCmd is GotoCmd); + GotoCmd successors = (GotoCmd)block.TransferCmd; + Contract.Assert(successors != null); + + if (successors.labelTargets != null) + foreach (Block nextBlock in successors.labelTargets) { + Contract.Assert(nextBlock != null); + if (path.Contains(nextBlock)) // If the current path has already seen the block, just skip it + continue; + // Otherwise we perform the DFS visit + path.Add(nextBlock); + DoDFSVisit(nextBlock, path, blocksInPath); + + Contract.Assert(nextBlock == path[path.Count - 1]); + path.RemoveAt(path.Count - 1); + } + + } + + #endregion + } + } +} diff --git a/Source/AbsInt/TrivialDomain.cs b/Source/AbsInt/TrivialDomain.cs index f9298e11..123bcefe 100644 --- a/Source/AbsInt/TrivialDomain.cs +++ b/Source/AbsInt/TrivialDomain.cs @@ -1,79 +1,79 @@ -using System; -using System.Numerics; -using System.Collections.Generic; -using System.Diagnostics.Contracts; - -namespace Microsoft.Boogie.AbstractInterpretation -{ - class TrivialDomain : NativeLattice - { - class E : NativeLattice.Element - { - public readonly bool IsTop; - public E(bool isTop) { - IsTop = isTop; - } - - public override Expr ToExpr() { - return Expr.Literal(IsTop); - } - } - - private E top = new E(true); - private E bottom = new E(false); - - public override Element Top { get { return top; } } - public override Element Bottom { get { return bottom; } } - - public override bool IsTop(Element element) { - var e = (E)element; - return e.IsTop; - } - public override bool IsBottom(Element element) { - var e = (E)element; - return !e.IsTop; - } - - public override bool Below(Element a, Element b) { - return IsBottom(a) || IsTop(b); - } - - public override Element Meet(Element a, Element b) { - if (IsBottom(b)) { - return b; - } else { - return a; - } - } - - public override Element Join(Element a, Element b) { - if (IsTop(b)) { - return b; - } else { - return a; - } - } - - public override Element Widen(Element a, Element b) { - return Join(a, b); // it's a finite domain, after all - } - - public override Element Constrain(Element element, Expr expr) { - var e = (E)element; - var lit = expr as LiteralExpr; - if (lit != null && lit.isBool && !(bool)lit.Val) { - return bottom; - } else { - return e; - } - } - - public override Element Update(Element element, AssignCmd cmd) { - return element; - } - - public override Element Eliminate(Element element, Variable v) { - return element; - } - } -} +using System; +using System.Numerics; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +namespace Microsoft.Boogie.AbstractInterpretation +{ + class TrivialDomain : NativeLattice + { + class E : NativeLattice.Element + { + public readonly bool IsTop; + public E(bool isTop) { + IsTop = isTop; + } + + public override Expr ToExpr() { + return Expr.Literal(IsTop); + } + } + + private E top = new E(true); + private E bottom = new E(false); + + public override Element Top { get { return top; } } + public override Element Bottom { get { return bottom; } } + + public override bool IsTop(Element element) { + var e = (E)element; + return e.IsTop; + } + public override bool IsBottom(Element element) { + var e = (E)element; + return !e.IsTop; + } + + public override bool Below(Element a, Element b) { + return IsBottom(a) || IsTop(b); + } + + public override Element Meet(Element a, Element b) { + if (IsBottom(b)) { + return b; + } else { + return a; + } + } + + public override Element Join(Element a, Element b) { + if (IsTop(b)) { + return b; + } else { + return a; + } + } + + public override Element Widen(Element a, Element b) { + return Join(a, b); // it's a finite domain, after all + } + + public override Element Constrain(Element element, Expr expr) { + var e = (E)element; + var lit = expr as LiteralExpr; + if (lit != null && lit.isBool && !(bool)lit.Val) { + return bottom; + } else { + return e; + } + } + + public override Element Update(Element element, AssignCmd cmd) { + return element; + } + + public override Element Eliminate(Element element, Variable v) { + return element; + } + } +} diff --git a/Source/AbsInt/cce.cs b/Source/AbsInt/cce.cs index 693d608c..627add75 100644 --- a/Source/AbsInt/cce.cs +++ b/Source/AbsInt/cce.cs @@ -1,62 +1,62 @@ - -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -using Microsoft.Boogie; - - /// - /// A class containing static methods to extend the functionality of Code Contracts - /// - -public static class cce { - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(VariableSeq collection) { - return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - } - - public class UnreachableException : Exception { - public UnreachableException() { - } - } - - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - - public static bool IsPeerConsistent(this object o) { - return true; - } - - public static bool IsConsistent(this object o) { - return true; - } - - public static bool IsExposable(this object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - } -} -public class PeerAttribute : System.Attribute { -} -public class RepAttribute : System.Attribute { -} -public class CapturedAttribute : System.Attribute { -} + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +using Microsoft.Boogie; + + /// + /// A class containing static methods to extend the functionality of Code Contracts + /// + +public static class cce { + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(VariableSeq collection) { + return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + } + + public class UnreachableException : Exception { + public UnreachableException() { + } + } + + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + + public static bool IsPeerConsistent(this object o) { + return true; + } + + public static bool IsConsistent(this object o) { + return true; + } + + public static bool IsExposable(this object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + } +} +public class PeerAttribute : System.Attribute { +} +public class RepAttribute : System.Attribute { +} +public class CapturedAttribute : System.Attribute { +} diff --git a/Source/BVD/App.config b/Source/BVD/App.config index fad249e4..8e156463 100644 --- a/Source/BVD/App.config +++ b/Source/BVD/App.config @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/Source/BVD/BVD.csproj b/Source/BVD/BVD.csproj index ccf52191..e83cfdd7 100644 --- a/Source/BVD/BVD.csproj +++ b/Source/BVD/BVD.csproj @@ -1,106 +1,106 @@ - - - - - Debug - AnyCPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797} - WinExe - Properties - Microsoft.Boogie.ModelViewer - BVD - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - 12.0.0 - 2.0 - - - AnyCPU - true - full - false - ..\..\Binaries\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - ..\..\Binaries\ - TRACE - prompt - 4 - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C} - ModelViewer - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - + + + + + Debug + AnyCPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797} + WinExe + Properties + Microsoft.Boogie.ModelViewer + BVD + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + 12.0.0 + 2.0 + + + AnyCPU + true + full + false + ..\..\Binaries\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\..\Binaries\ + TRACE + prompt + 4 + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + + + + + + + + + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C} + ModelViewer + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + diff --git a/Source/BVD/Program.cs b/Source/BVD/Program.cs index 669ea995..a606c863 100644 --- a/Source/BVD/Program.cs +++ b/Source/BVD/Program.cs @@ -1,28 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; - -namespace Microsoft.Boogie.ModelViewer -{ - static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - try - { - Application.Run(new Main(System.Environment.GetCommandLineArgs())); - } - catch (Exception exc) - { - MessageBox.Show(exc.Message, "Model Viewer Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace Microsoft.Boogie.ModelViewer +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + try + { + Application.Run(new Main(System.Environment.GetCommandLineArgs())); + } + catch (Exception exc) + { + MessageBox.Show(exc.Message, "Model Viewer Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + } + } + } +} diff --git a/Source/BVD/Properties/AssemblyInfo.cs b/Source/BVD/Properties/AssemblyInfo.cs index 3512374e..0e9c953a 100644 --- a/Source/BVD/Properties/AssemblyInfo.cs +++ b/Source/BVD/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BVD")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BVD")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("00610a12-cf4c-4c29-af30-31a99d22b9d8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BVD")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BVD")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("00610a12-cf4c-4c29-af30-31a99d22b9d8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Basetypes/Basetypes.csproj b/Source/Basetypes/Basetypes.csproj index 8e6310e6..5e46877a 100644 --- a/Source/Basetypes/Basetypes.csproj +++ b/Source/Basetypes/Basetypes.csproj @@ -1,203 +1,203 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Library - Properties - Basetypes - Basetypes - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for Basetypes.ruleset - true - 4 - false - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\Basetypes.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - - - - - - - - version.cs - - - - - - - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Library + Properties + Basetypes + Basetypes + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for Basetypes.ruleset + true + 4 + false + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\Basetypes.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + + + + + + + + version.cs + + + + + + + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + diff --git a/Source/Basetypes/BigDec.cs b/Source/Basetypes/BigDec.cs index 0aeea8b1..e4666793 100644 --- a/Source/Basetypes/BigDec.cs +++ b/Source/Basetypes/BigDec.cs @@ -1,380 +1,380 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.Diagnostics.Contracts; -using System.Diagnostics; - - -namespace Microsoft.Basetypes { - using BIM = System.Numerics.BigInteger; - - - /// - /// A representation of decimal values. - /// - public struct BigDec { - - // the internal representation - [Rep] - internal readonly BIM mantissa; - [Rep] - internal readonly int exponent; - - public BIM Mantissa { - get { - return mantissa; - } - } - - public int Exponent { - get { - return exponent; - } - } - - public static readonly BigDec ZERO = FromInt(0); - private static readonly BIM ten = new BIM(10); - - - //////////////////////////////////////////////////////////////////////////// - // Constructors - - [Pure] - public static BigDec FromInt(int v) { - return new BigDec(v, 0); - } - - [Pure] - public static BigDec FromBigInt(BIM v) { - return new BigDec(v, 0); - } - - [Pure] - public static BigDec FromString(string v) { - if (v == null) throw new FormatException(); - - BIM integral = BIM.Zero; - BIM fraction = BIM.Zero; - int exponent = 0; - - int len = v.Length; - - int i = v.IndexOf('e'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); - len = i; - } - - int fractionLen = 0; - i = v.IndexOf('.'); - if (i >= 0) { - if (i + 1 == v.Length) throw new FormatException(); - fractionLen = len - i - 1; - fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); - len = i; - } - - integral = BIM.Parse(v.Substring(0, len)); - - if (!fraction.IsZero) { - while (fractionLen > 0) { - integral = integral * ten; - exponent = exponent - 1; - fractionLen = fractionLen - 1; - } - } - - if (integral.Sign == -1) { - return new BigDec(integral - fraction, exponent); - } - else { - return new BigDec(integral + fraction, exponent); - } - } - - internal BigDec(BIM mantissa, int exponent) { - if (mantissa.IsZero) { - this.mantissa = mantissa; - this.exponent = 0; - } - else { - while (mantissa % ten == BIM.Zero) { - mantissa = mantissa / ten; - exponent = exponent + 1; - } - this.mantissa = mantissa; - this.exponent = exponent; - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic object operations - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BigDec)) - return false; - - return (this == (BigDec)obj); - } - - [Pure] - public override int GetHashCode() { - return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); - } - - - //////////////////////////////////////////////////////////////////////////// - // Conversion operations - - // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). - /// - /// Computes the floor and ceiling of this BigDec. Note the choice of rounding towards negative - /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. - /// - /// The Floor (rounded towards negative infinity) - /// Ceiling (rounded towards positive infinity) - public void FloorCeiling(out BIM floor, out BIM ceiling) { - BIM n = this.mantissa; - int e = this.exponent; - if (n.IsZero) { - floor = ceiling = n; - } else if (0 <= e) { - // it's an integer - for (; 0 < e; e--) { - n = n * ten; - } - floor = ceiling = n; - } else { - // it's a non-zero integer, so the ceiling is one more than the floor - for (; e < 0 && !n.IsZero; e++) { - n = n / ten; // Division rounds towards negative infinity - } - - if (this.mantissa >= 0) { - floor = n; - ceiling = n + 1; - } else { - ceiling = n; - floor = n - 1; - } - } - Debug.Assert(floor <= ceiling, "Invariant was not maintained"); - } - - [Pure] - public String ToDecimalString(int maxDigits) { - string s = this.mantissa.ToString(); - int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; - BIM max = BIM.Pow(10, maxDigits); - BIM min = -max; - - if (this.exponent >= 0) { - if (maxDigits < digits || maxDigits - digits < this.exponent) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); - } - else { - return String.Format("{0}{1}.0", s, new string('0', this.exponent)); - } - } - else { - int exp = -this.exponent; - - if (exp < digits) { - int intDigits = digits - exp; - if (maxDigits < intDigits) { - return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); - } - else { - int fracDigits = Math.Min(maxDigits, digits - intDigits); - return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); - } - } - else { - int fracDigits = Math.Min(maxDigits, digits); - return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); - } - } - } - - [Pure] - public string ToDecimalString() { - string m = this.mantissa.ToString(); - var e = this.exponent; - if (0 <= this.exponent) { - return m + Zeros(e) + ".0"; - } else { - e = -e; - // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) - var maxK = e < m.Length ? e : m.Length - 1; - var last = m.Length - 1; - var k = 0; - while (k < maxK && m[last - k] == '0') { - k++; - } - if (0 < k) { - // chop off the suffix of k zeros from m and adjust e accordingly - m = m.Substring(0, m.Length - k); - e -= k; - } - if (e == 0) { - return m; - } else if (e < m.Length) { - var n = m.Length - e; - return m.Substring(0, n) + "." + m.Substring(n); - } else { - return "0." + Zeros(e - m.Length) + m; - } - } - } - - [Pure] - public static string Zeros(int n) { - Contract.Requires(0 <= n); - if (n <= 10) { - var tenZeros = "0000000000"; - return tenZeros.Substring(0, n); - } else { - var d = n / 2; - var s = Zeros(d); - if (n % 2 == 0) { - return s + s; - } else { - return s + s + "0"; - } - } - } - - - //////////////////////////////////////////////////////////////////////////// - // Basic arithmetic operations - - [Pure] - public BigDec Abs { - get { - return new BigDec(BIM.Abs(this.mantissa), this.exponent); - } - } - - [Pure] - public BigDec Negate { - get { - return new BigDec(BIM.Negate(this.mantissa), this.exponent); - } - } - - [Pure] - public static BigDec operator -(BigDec x) { - return x.Negate; - } - - [Pure] - public static BigDec operator +(BigDec x, BigDec y) { - BIM m1 = x.mantissa; - int e1 = x.exponent; - BIM m2 = y.mantissa; - int e2 = y.exponent; - if (e2 < e1) { - m1 = y.mantissa; - e1 = y.exponent; - m2 = x.mantissa; - e2 = x.exponent; - } - - while (e2 > e1) { - m2 = m2 * ten; - e2 = e2 - 1; - } - - return new BigDec(m1 + m2, e1); - } - - [Pure] - public static BigDec operator -(BigDec x, BigDec y) { - return x + y.Negate; - } - - [Pure] - public static BigDec operator *(BigDec x, BigDec y) { - return new BigDec(x.mantissa * y.mantissa, x.exponent + y.exponent); - } - - - //////////////////////////////////////////////////////////////////////////// - // Some basic comparison operations - - public bool IsPositive { - get { - return (this.mantissa > BIM.Zero); - } - } - - public bool IsNegative { - get { - return (this.mantissa < BIM.Zero); - } - } - - public bool IsZero { - get { - return this.mantissa.IsZero; - } - } - - [Pure] - public int CompareTo(BigDec that) { - if (this.mantissa == that.mantissa && this.exponent == that.exponent) { - return 0; - } - else { - BigDec d = this - that; - return d.IsNegative ? -1 : 1; - } - } - - [Pure] - public static bool operator ==(BigDec x, BigDec y) { - return x.CompareTo(y) == 0; - } - - [Pure] - public static bool operator !=(BigDec x, BigDec y) { - return x.CompareTo(y) != 0; - } - - [Pure] - public static bool operator <(BigDec x, BigDec y) { - return x.CompareTo(y) < 0; - } - - [Pure] - public static bool operator >(BigDec x, BigDec y) { - return x.CompareTo(y) > 0; - } - - [Pure] - public static bool operator <=(BigDec x, BigDec y) { - return x.CompareTo(y) <= 0; - } - - [Pure] - public static bool operator >=(BigDec x, BigDec y) { - return x.CompareTo(y) >= 0; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + + +namespace Microsoft.Basetypes { + using BIM = System.Numerics.BigInteger; + + + /// + /// A representation of decimal values. + /// + public struct BigDec { + + // the internal representation + [Rep] + internal readonly BIM mantissa; + [Rep] + internal readonly int exponent; + + public BIM Mantissa { + get { + return mantissa; + } + } + + public int Exponent { + get { + return exponent; + } + } + + public static readonly BigDec ZERO = FromInt(0); + private static readonly BIM ten = new BIM(10); + + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + [Pure] + public static BigDec FromInt(int v) { + return new BigDec(v, 0); + } + + [Pure] + public static BigDec FromBigInt(BIM v) { + return new BigDec(v, 0); + } + + [Pure] + public static BigDec FromString(string v) { + if (v == null) throw new FormatException(); + + BIM integral = BIM.Zero; + BIM fraction = BIM.Zero; + int exponent = 0; + + int len = v.Length; + + int i = v.IndexOf('e'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + exponent = Int32.Parse(v.Substring(i + 1, len - i - 1)); + len = i; + } + + int fractionLen = 0; + i = v.IndexOf('.'); + if (i >= 0) { + if (i + 1 == v.Length) throw new FormatException(); + fractionLen = len - i - 1; + fraction = BIM.Parse(v.Substring(i + 1, fractionLen)); + len = i; + } + + integral = BIM.Parse(v.Substring(0, len)); + + if (!fraction.IsZero) { + while (fractionLen > 0) { + integral = integral * ten; + exponent = exponent - 1; + fractionLen = fractionLen - 1; + } + } + + if (integral.Sign == -1) { + return new BigDec(integral - fraction, exponent); + } + else { + return new BigDec(integral + fraction, exponent); + } + } + + internal BigDec(BIM mantissa, int exponent) { + if (mantissa.IsZero) { + this.mantissa = mantissa; + this.exponent = 0; + } + else { + while (mantissa % ten == BIM.Zero) { + mantissa = mantissa / ten; + exponent = exponent + 1; + } + this.mantissa = mantissa; + this.exponent = exponent; + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic object operations + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BigDec)) + return false; + + return (this == (BigDec)obj); + } + + [Pure] + public override int GetHashCode() { + return this.mantissa.GetHashCode() * 13 + this.exponent.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}e{1}", this.mantissa.ToString(), this.exponent.ToString()); + } + + + //////////////////////////////////////////////////////////////////////////// + // Conversion operations + + // ``floor`` rounds towards negative infinity (like SMT-LIBv2's to_int). + /// + /// Computes the floor and ceiling of this BigDec. Note the choice of rounding towards negative + /// infinity rather than zero for floor is because SMT-LIBv2's to_int function floors this way. + /// + /// The Floor (rounded towards negative infinity) + /// Ceiling (rounded towards positive infinity) + public void FloorCeiling(out BIM floor, out BIM ceiling) { + BIM n = this.mantissa; + int e = this.exponent; + if (n.IsZero) { + floor = ceiling = n; + } else if (0 <= e) { + // it's an integer + for (; 0 < e; e--) { + n = n * ten; + } + floor = ceiling = n; + } else { + // it's a non-zero integer, so the ceiling is one more than the floor + for (; e < 0 && !n.IsZero; e++) { + n = n / ten; // Division rounds towards negative infinity + } + + if (this.mantissa >= 0) { + floor = n; + ceiling = n + 1; + } else { + ceiling = n; + floor = n - 1; + } + } + Debug.Assert(floor <= ceiling, "Invariant was not maintained"); + } + + [Pure] + public String ToDecimalString(int maxDigits) { + string s = this.mantissa.ToString(); + int digits = (this.mantissa >= 0) ? s.Length : s.Length - 1; + BIM max = BIM.Pow(10, maxDigits); + BIM min = -max; + + if (this.exponent >= 0) { + if (maxDigits < digits || maxDigits - digits < this.exponent) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + return String.Format("{0}{1}.0", s, new string('0', this.exponent)); + } + } + else { + int exp = -this.exponent; + + if (exp < digits) { + int intDigits = digits - exp; + if (maxDigits < intDigits) { + return String.Format("{0}.0", (this.mantissa >= 0) ? max.ToString() : min.ToString()); + } + else { + int fracDigits = Math.Min(maxDigits, digits - intDigits); + return String.Format("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits)); + } + } + else { + int fracDigits = Math.Min(maxDigits, digits); + return String.Format("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits)); + } + } + } + + [Pure] + public string ToDecimalString() { + string m = this.mantissa.ToString(); + var e = this.exponent; + if (0 <= this.exponent) { + return m + Zeros(e) + ".0"; + } else { + e = -e; + // compute k to be the longest suffix of m consisting of all zeros (but no longer than e, and not the entire string) + var maxK = e < m.Length ? e : m.Length - 1; + var last = m.Length - 1; + var k = 0; + while (k < maxK && m[last - k] == '0') { + k++; + } + if (0 < k) { + // chop off the suffix of k zeros from m and adjust e accordingly + m = m.Substring(0, m.Length - k); + e -= k; + } + if (e == 0) { + return m; + } else if (e < m.Length) { + var n = m.Length - e; + return m.Substring(0, n) + "." + m.Substring(n); + } else { + return "0." + Zeros(e - m.Length) + m; + } + } + } + + [Pure] + public static string Zeros(int n) { + Contract.Requires(0 <= n); + if (n <= 10) { + var tenZeros = "0000000000"; + return tenZeros.Substring(0, n); + } else { + var d = n / 2; + var s = Zeros(d); + if (n % 2 == 0) { + return s + s; + } else { + return s + s + "0"; + } + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + [Pure] + public BigDec Abs { + get { + return new BigDec(BIM.Abs(this.mantissa), this.exponent); + } + } + + [Pure] + public BigDec Negate { + get { + return new BigDec(BIM.Negate(this.mantissa), this.exponent); + } + } + + [Pure] + public static BigDec operator -(BigDec x) { + return x.Negate; + } + + [Pure] + public static BigDec operator +(BigDec x, BigDec y) { + BIM m1 = x.mantissa; + int e1 = x.exponent; + BIM m2 = y.mantissa; + int e2 = y.exponent; + if (e2 < e1) { + m1 = y.mantissa; + e1 = y.exponent; + m2 = x.mantissa; + e2 = x.exponent; + } + + while (e2 > e1) { + m2 = m2 * ten; + e2 = e2 - 1; + } + + return new BigDec(m1 + m2, e1); + } + + [Pure] + public static BigDec operator -(BigDec x, BigDec y) { + return x + y.Negate; + } + + [Pure] + public static BigDec operator *(BigDec x, BigDec y) { + return new BigDec(x.mantissa * y.mantissa, x.exponent + y.exponent); + } + + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public bool IsPositive { + get { + return (this.mantissa > BIM.Zero); + } + } + + public bool IsNegative { + get { + return (this.mantissa < BIM.Zero); + } + } + + public bool IsZero { + get { + return this.mantissa.IsZero; + } + } + + [Pure] + public int CompareTo(BigDec that) { + if (this.mantissa == that.mantissa && this.exponent == that.exponent) { + return 0; + } + else { + BigDec d = this - that; + return d.IsNegative ? -1 : 1; + } + } + + [Pure] + public static bool operator ==(BigDec x, BigDec y) { + return x.CompareTo(y) == 0; + } + + [Pure] + public static bool operator !=(BigDec x, BigDec y) { + return x.CompareTo(y) != 0; + } + + [Pure] + public static bool operator <(BigDec x, BigDec y) { + return x.CompareTo(y) < 0; + } + + [Pure] + public static bool operator >(BigDec x, BigDec y) { + return x.CompareTo(y) > 0; + } + + [Pure] + public static bool operator <=(BigDec x, BigDec y) { + return x.CompareTo(y) <= 0; + } + + [Pure] + public static bool operator >=(BigDec x, BigDec y) { + return x.CompareTo(y) >= 0; + } + } +} diff --git a/Source/Basetypes/BigNum.cs b/Source/Basetypes/BigNum.cs index ff676bc6..4469f149 100644 --- a/Source/Basetypes/BigNum.cs +++ b/Source/Basetypes/BigNum.cs @@ -1,361 +1,361 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.Diagnostics.Contracts; - - -namespace Microsoft.Basetypes { - using BIM = System.Numerics.BigInteger; - - /// - /// A thin wrapper around System.Numerics.BigInteger - /// (to be able to define equality, etc. properly) - /// - public struct BigNum { - - // the internal representation - [Rep] - internal readonly System.Numerics.BigInteger val; - public static readonly BigNum ZERO = new BigNum(BIM.Zero); - public static readonly BigNum ONE = new BigNum(BIM.One); - public static readonly BigNum MINUS_ONE = new BigNum(-BIM.One); - - [Pure] - public static BigNum FromInt(int v) { - return new BigNum(new BIM(v)); - } - - [Pure] - public static BigNum FromUInt(uint v) { - return new BigNum(new BIM((long)v)); - } - - [Pure] - public static BigNum FromLong(long v) { - return new BigNum(new BIM(v)); - } - - [Pure] - public static BigNum FromBigInt(System.Numerics.BigInteger v) { - return new BigNum(v); - } - - [Pure] - public static BigNum FromULong(ulong v) { - return FromString("" + v); - } - - [Pure] - public static BigNum FromString(string v) { - try { - return new BigNum(BIM.Parse(v)); - } catch (System.ArgumentException) { - throw new FormatException(); - } - } - - public static bool TryParse(string v, out BigNum res) { - try { - res = BigNum.FromString(v); - return true; - } catch (FormatException) { - res = ZERO; - return false; - } - } - - // Convert to int, without checking whether overflows occur - public int ToInt { - get { - return (int)val; - } - } - - public BIM ToBigInteger { - get { - return val; - } - } - - // Convert to int; assert that no overflows occur - public int ToIntSafe { - get { - Contract.Assert(this.InInt32); - return this.ToInt; - } - } - - public Rational ToRational { - get { - return Rational.FromBignum(this); - } - } - - public byte[] ToByteArray() - { - return this.val.ToByteArray(); - } - - internal BigNum(System.Numerics.BigInteger val) { - this.val = val; - } - - public static bool operator ==(BigNum x, BigNum y) { - return (x.val == y.val); - } - - public static bool operator !=(BigNum x, BigNum y) { - return !(x.val == y.val); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BigNum)) - return false; - - BigNum other = (BigNum)obj; - return (this.val == other.val); - } - - [Pure] - public override int GetHashCode() { - return this.val.GetHashCode(); - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(val.ToString()); - } - - ////////////////////////////////////////////////////////////////////////////// - // Very limited support for format strings - // Note: Negative integers are linearised with a minus "-" in hexadecimal, - // not in 2-complement notation (in contrast to what the method - // int32.ToString(format) does) - - [Pure] - public string/*!*/ ToString(string/*!*/ format) { - Contract.Requires(format != null); - Contract.Ensures(Contract.Result() != null); - if (format.StartsWith("d") || format.StartsWith("D")) { - string res = this.Abs.ToString(); - Contract.Assert(res != null); - return addMinus(this.Signum, - prefixWithZeros(extractPrecision(format), res)); - } else if (format.StartsWith("x") || format.StartsWith("X")) { - string res = this.toHex(format.Substring(0, 1)); - Contract.Assert(res != null); - return addMinus(this.Signum, - prefixWithZeros(extractPrecision(format), res)); - } else { - throw new FormatException("Format " + format + " is not supported"); - } - } - - private static readonly System.Numerics.BigInteger BI_2_TO_24 = new BIM(0x1000000); - - [Pure] - private string/*!*/ toHex(string/*!*/ format) { - Contract.Requires(format != null); - Contract.Ensures(Contract.Result() != null); - string res = ""; - System.Numerics.BigInteger rem = this.Abs.val; - - while (rem > BIM.Zero) { - res = ((int)(rem % BI_2_TO_24)).ToString(format) + res; - rem = rem / BI_2_TO_24; - } - - return res; - } - - [Pure] - private int extractPrecision(string/*!*/ format) { - Contract.Requires(format != null); - if (format.Length > 1) - // will throw a FormatException if the precision is invalid; - // that is ok - return Int32.Parse(format.Substring(1)); - // always output at least one digit - return 1; - } - - [Pure] - private string/*!*/ addMinus(int signum, string/*!*/ suffix) { - Contract.Requires(suffix != null); - Contract.Ensures(Contract.Result() != null); - if (signum < 0) - return "-" + suffix; - return suffix; - } - - [Pure] - private string/*!*/ prefixWithZeros(int minLength, string/*!*/ suffix) { - Contract.Requires(suffix != null); - Contract.Ensures(Contract.Result() != null); - StringBuilder res = new StringBuilder(); - while (res.Length + suffix.Length < minLength) - res.Append("0"); - res.Append(suffix); - return res.ToString(); - } - - //////////////////////////////////////////////////////////////////////////// - // Basic arithmetic operations - - public BigNum Abs { - get { - return new BigNum(BIM.Abs(this.val)); - } - } - - public BigNum Neg { - get { - return new BigNum(-this.val); - } - } - - [Pure] - public static BigNum operator -(BigNum x) { - return x.Neg; - } - - [Pure] - public static BigNum operator +(BigNum x, BigNum y) { - return new BigNum(x.val + y.val); - } - - [Pure] - public static BigNum operator -(BigNum x, BigNum y) { - return new BigNum(x.val - y.val); - } - - [Pure] - public static BigNum operator *(BigNum x, BigNum y) { - return new BigNum(x.val * y.val); - } - - // TODO: check that this has a proper semantics (which? :-)) - [Pure] - public static BigNum operator /(BigNum x, BigNum y) { - return new BigNum(x.val / y.val); - } - - // TODO: check that this has a proper semantics (which? :-)) - [Pure] - public static BigNum operator %(BigNum x, BigNum y) { - return new BigNum(x.val - ((x.val / y.val) * y.val)); - } - - [Pure] - public BigNum Min(BigNum that) { - return new BigNum(this.val <= that.val ? this.val : that.val); - } - - [Pure] - public BigNum Max(BigNum that) { - return new BigNum(this.val >= that.val ? this.val : that.val); - } - - /// - /// Returns the greatest common divisor of this and _y. - /// - /// - /// - public BigNum Gcd(BigNum _y) { - Contract.Ensures(!Contract.Result().IsNegative); - BigNum x = this.Abs; - BigNum y = _y.Abs; - - while (true) { - if (x < y) { - y = y % x; - if (y.IsZero) { - return x; - } - } else { - x = x % y; - if (x.IsZero) { - return y; - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // Some basic comparison operations - - public int Signum { - get { - return this.val.Sign; - } - } - - public bool IsPositive { - get { - return (this.val > BIM.Zero); - } - } - - public bool IsNegative { - get { - return (this.val < BIM.Zero); - } - } - - public bool IsZero { - get { - return this.val.IsZero; - } - } - - [Pure] - public int CompareTo(BigNum that) { - if (this.val == that.val) - return 0; - if (this.val < that.val) - return -1; - return 1; - } - - [Pure] - public static bool operator <(BigNum x, BigNum y) { - return (x.val < y.val); - } - - [Pure] - public static bool operator >(BigNum x, BigNum y) { - return (x.val > y.val); - } - - [Pure] - public static bool operator <=(BigNum x, BigNum y) { - return (x.val <= y.val); - } - - [Pure] - public static bool operator >=(BigNum x, BigNum y) { - return (x.val >= y.val); - } - - - private static readonly System.Numerics.BigInteger MaxInt32 = - new BIM(Int32.MaxValue); - private static readonly System.Numerics.BigInteger MinInt32 = - new BIM(Int32.MinValue); - - public bool InInt32 { - get { - return (val >= MinInt32) && (val <= MaxInt32); - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.Diagnostics.Contracts; + + +namespace Microsoft.Basetypes { + using BIM = System.Numerics.BigInteger; + + /// + /// A thin wrapper around System.Numerics.BigInteger + /// (to be able to define equality, etc. properly) + /// + public struct BigNum { + + // the internal representation + [Rep] + internal readonly System.Numerics.BigInteger val; + public static readonly BigNum ZERO = new BigNum(BIM.Zero); + public static readonly BigNum ONE = new BigNum(BIM.One); + public static readonly BigNum MINUS_ONE = new BigNum(-BIM.One); + + [Pure] + public static BigNum FromInt(int v) { + return new BigNum(new BIM(v)); + } + + [Pure] + public static BigNum FromUInt(uint v) { + return new BigNum(new BIM((long)v)); + } + + [Pure] + public static BigNum FromLong(long v) { + return new BigNum(new BIM(v)); + } + + [Pure] + public static BigNum FromBigInt(System.Numerics.BigInteger v) { + return new BigNum(v); + } + + [Pure] + public static BigNum FromULong(ulong v) { + return FromString("" + v); + } + + [Pure] + public static BigNum FromString(string v) { + try { + return new BigNum(BIM.Parse(v)); + } catch (System.ArgumentException) { + throw new FormatException(); + } + } + + public static bool TryParse(string v, out BigNum res) { + try { + res = BigNum.FromString(v); + return true; + } catch (FormatException) { + res = ZERO; + return false; + } + } + + // Convert to int, without checking whether overflows occur + public int ToInt { + get { + return (int)val; + } + } + + public BIM ToBigInteger { + get { + return val; + } + } + + // Convert to int; assert that no overflows occur + public int ToIntSafe { + get { + Contract.Assert(this.InInt32); + return this.ToInt; + } + } + + public Rational ToRational { + get { + return Rational.FromBignum(this); + } + } + + public byte[] ToByteArray() + { + return this.val.ToByteArray(); + } + + internal BigNum(System.Numerics.BigInteger val) { + this.val = val; + } + + public static bool operator ==(BigNum x, BigNum y) { + return (x.val == y.val); + } + + public static bool operator !=(BigNum x, BigNum y) { + return !(x.val == y.val); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BigNum)) + return false; + + BigNum other = (BigNum)obj; + return (this.val == other.val); + } + + [Pure] + public override int GetHashCode() { + return this.val.GetHashCode(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(val.ToString()); + } + + ////////////////////////////////////////////////////////////////////////////// + // Very limited support for format strings + // Note: Negative integers are linearised with a minus "-" in hexadecimal, + // not in 2-complement notation (in contrast to what the method + // int32.ToString(format) does) + + [Pure] + public string/*!*/ ToString(string/*!*/ format) { + Contract.Requires(format != null); + Contract.Ensures(Contract.Result() != null); + if (format.StartsWith("d") || format.StartsWith("D")) { + string res = this.Abs.ToString(); + Contract.Assert(res != null); + return addMinus(this.Signum, + prefixWithZeros(extractPrecision(format), res)); + } else if (format.StartsWith("x") || format.StartsWith("X")) { + string res = this.toHex(format.Substring(0, 1)); + Contract.Assert(res != null); + return addMinus(this.Signum, + prefixWithZeros(extractPrecision(format), res)); + } else { + throw new FormatException("Format " + format + " is not supported"); + } + } + + private static readonly System.Numerics.BigInteger BI_2_TO_24 = new BIM(0x1000000); + + [Pure] + private string/*!*/ toHex(string/*!*/ format) { + Contract.Requires(format != null); + Contract.Ensures(Contract.Result() != null); + string res = ""; + System.Numerics.BigInteger rem = this.Abs.val; + + while (rem > BIM.Zero) { + res = ((int)(rem % BI_2_TO_24)).ToString(format) + res; + rem = rem / BI_2_TO_24; + } + + return res; + } + + [Pure] + private int extractPrecision(string/*!*/ format) { + Contract.Requires(format != null); + if (format.Length > 1) + // will throw a FormatException if the precision is invalid; + // that is ok + return Int32.Parse(format.Substring(1)); + // always output at least one digit + return 1; + } + + [Pure] + private string/*!*/ addMinus(int signum, string/*!*/ suffix) { + Contract.Requires(suffix != null); + Contract.Ensures(Contract.Result() != null); + if (signum < 0) + return "-" + suffix; + return suffix; + } + + [Pure] + private string/*!*/ prefixWithZeros(int minLength, string/*!*/ suffix) { + Contract.Requires(suffix != null); + Contract.Ensures(Contract.Result() != null); + StringBuilder res = new StringBuilder(); + while (res.Length + suffix.Length < minLength) + res.Append("0"); + res.Append(suffix); + return res.ToString(); + } + + //////////////////////////////////////////////////////////////////////////// + // Basic arithmetic operations + + public BigNum Abs { + get { + return new BigNum(BIM.Abs(this.val)); + } + } + + public BigNum Neg { + get { + return new BigNum(-this.val); + } + } + + [Pure] + public static BigNum operator -(BigNum x) { + return x.Neg; + } + + [Pure] + public static BigNum operator +(BigNum x, BigNum y) { + return new BigNum(x.val + y.val); + } + + [Pure] + public static BigNum operator -(BigNum x, BigNum y) { + return new BigNum(x.val - y.val); + } + + [Pure] + public static BigNum operator *(BigNum x, BigNum y) { + return new BigNum(x.val * y.val); + } + + // TODO: check that this has a proper semantics (which? :-)) + [Pure] + public static BigNum operator /(BigNum x, BigNum y) { + return new BigNum(x.val / y.val); + } + + // TODO: check that this has a proper semantics (which? :-)) + [Pure] + public static BigNum operator %(BigNum x, BigNum y) { + return new BigNum(x.val - ((x.val / y.val) * y.val)); + } + + [Pure] + public BigNum Min(BigNum that) { + return new BigNum(this.val <= that.val ? this.val : that.val); + } + + [Pure] + public BigNum Max(BigNum that) { + return new BigNum(this.val >= that.val ? this.val : that.val); + } + + /// + /// Returns the greatest common divisor of this and _y. + /// + /// + /// + public BigNum Gcd(BigNum _y) { + Contract.Ensures(!Contract.Result().IsNegative); + BigNum x = this.Abs; + BigNum y = _y.Abs; + + while (true) { + if (x < y) { + y = y % x; + if (y.IsZero) { + return x; + } + } else { + x = x % y; + if (x.IsZero) { + return y; + } + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // Some basic comparison operations + + public int Signum { + get { + return this.val.Sign; + } + } + + public bool IsPositive { + get { + return (this.val > BIM.Zero); + } + } + + public bool IsNegative { + get { + return (this.val < BIM.Zero); + } + } + + public bool IsZero { + get { + return this.val.IsZero; + } + } + + [Pure] + public int CompareTo(BigNum that) { + if (this.val == that.val) + return 0; + if (this.val < that.val) + return -1; + return 1; + } + + [Pure] + public static bool operator <(BigNum x, BigNum y) { + return (x.val < y.val); + } + + [Pure] + public static bool operator >(BigNum x, BigNum y) { + return (x.val > y.val); + } + + [Pure] + public static bool operator <=(BigNum x, BigNum y) { + return (x.val <= y.val); + } + + [Pure] + public static bool operator >=(BigNum x, BigNum y) { + return (x.val >= y.val); + } + + + private static readonly System.Numerics.BigInteger MaxInt32 = + new BIM(Int32.MaxValue); + private static readonly System.Numerics.BigInteger MinInt32 = + new BIM(Int32.MinValue); + + public bool InInt32 { + get { + return (val >= MinInt32) && (val <= MaxInt32); + } + } + } +} diff --git a/Source/Basetypes/Rational.cs b/Source/Basetypes/Rational.cs index cd0eddce..ef59cf4f 100644 --- a/Source/Basetypes/Rational.cs +++ b/Source/Basetypes/Rational.cs @@ -1,248 +1,248 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Diagnostics.Contracts; - -namespace Microsoft.Basetypes { - /// - /// The representation of a rational number. - /// - public struct Rational { - public static readonly Rational ZERO = Rational.FromInts(0, 1); - public static readonly Rational ONE = Rational.FromInts(1, 1); - public static readonly Rational MINUS_ONE = Rational.FromInts(-1, 1); - - private BigNum numerator, denominator; - - // int numerator; - // int denominator; - - - // invariant: 0 < denominator || (numerator == 0 && denominator == 0); - // invariant: numerator != 0 ==> gcd(abs(numerator),denominator) == 1; - // invariant: numerator == 0 ==> denominator == 1 || denominator == 0; - - public static Rational FromInt(int x) { - return FromBignum(BigNum.FromInt(x)); - } - - public static Rational FromBignum(BigNum n) - { - return new Rational(n, BigNum.ONE); - } - - private Rational(BigNum num, BigNum den) - { - Contract.Assert(den.Signum > 0); - Contract.Assert(num == BigNum.ZERO || num.Gcd(den) == BigNum.ONE); - numerator = num; - denominator = den; - } - - public static Rational FromBignums(BigNum num, BigNum den) { - Contract.Assert(!den.IsZero); - if (num == BigNum.ZERO) - return ZERO; - if (den.Signum < 0) { - den = -den; - num = -num; - } - if (den == BigNum.ONE) - return new Rational(num, den); - var gcd = num.Gcd(den); - if (gcd == BigNum.ONE) - return new Rational(num, den); - return new Rational(num / gcd, den / gcd); - } - - public static Rational FromInts(int num, int den) { - return FromBignums(BigNum.FromInt(num), BigNum.FromInt(den)); - } - - /// - /// Returns the absolute value of the rational. - /// - public Rational Abs() { - Contract.Ensures(Contract.Result().IsNonNegative); - if (IsNonNegative) { - return this; - } else { - return -this; - } - } - - /// - /// Returns a rational whose numerator and denominator, resepctively, are the Gcd - /// of the numerators and denominators of r and s. If one of r and s is 0, the absolute - /// value of the other is returned. If both are 0, 1 is returned. - /// - public static Rational Gcd(Rational r, Rational s) { - Contract.Ensures(Contract.Result().IsPositive); - if (r.IsZero) { - if (s.IsZero) { - return ONE; - } else { - return s.Abs(); - } - } else if (s.IsZero) { - return r.Abs(); - } else { - return new Rational(r.Numerator.Gcd(s.Numerator), - r.Denominator.Gcd(s.Denominator)); - } - } - - public BigNum Numerator { get { return numerator; } } - public BigNum Denominator { get { return denominator == BigNum.ZERO ? BigNum.ONE : denominator; } } - - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - return String.Format("{0}/{1}", Numerator, Denominator); - } - - - public static bool operator ==(Rational r, Rational s) { - return r.Numerator == s.Numerator && r.Denominator == s.Denominator; - } - - public static bool operator !=(Rational r, Rational s) { - return !(r == s); - } - - public override bool Equals(object obj) { - if (obj == null) - return false; - return obj is Rational && (Rational)obj == this; - } - - public override int GetHashCode() { - return this.Numerator.GetHashCode() * 13 + this.Denominator.GetHashCode(); - } - - public int Signum { - get { - return this.Numerator.Signum; - } - } - - public bool IsZero { - get { - return Signum == 0; - } - } - - public bool IsNonZero { - get { - return Signum != 0; - } - } - - public bool IsIntegral { - get { - return Denominator == BigNum.ONE; - } - } - - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public bool HasValue(int n) { - return this == FromInt(n); - } - - /// - /// Returns the rational as an integer. Requires the rational to be integral. - /// - public int AsInteger { - get { - Contract.Assert(this.IsIntegral); - return Numerator.ToIntSafe; - } - } - - public BigNum AsBigNum { - get { - Contract.Assert(this.IsIntegral); - return Numerator; - } - } - - public double AsDouble { - [Pure] - get { - if (this.IsZero) { - return 0.0; - } else { - return (double)Numerator.ToIntSafe / (double)Denominator.ToIntSafe; - } - } - } - - public bool IsNegative { - [Pure] - get { - return Signum < 0; - } - } - - public bool IsPositive { - [Pure] - get { - return 0 < Signum; - } - } - - public bool IsNonNegative { - [Pure] - get { - return 0 <= Signum; - } - } - - public static Rational operator -(Rational r) - { - return new Rational(-r.Numerator, r.Denominator); - } - - public static Rational operator /(Rational r, Rational s) - { - return FromBignums(r.Numerator * s.Denominator, r.Denominator * s.Numerator); - } - - public static Rational operator -(Rational r, Rational s) - { - return r + (-s); - } - - public static Rational operator +(Rational r, Rational s) - { - return FromBignums(r.Numerator * s.Denominator + s.Numerator * r.Denominator, r.Denominator * s.Denominator); - } - - public static Rational operator *(Rational r, Rational s) - { - return FromBignums(r.Numerator * s.Numerator, r.Denominator * s.Denominator); - } - - public static bool operator <(Rational r, Rational s) - { - return (r - s).Signum < 0; - } - - public static bool operator <=(Rational r, Rational s) - { - return !(r > s); - } - - public static bool operator >=(Rational r, Rational s) { - return !(r < s); - } - - public static bool operator >(Rational r, Rational s) { - return s < r; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Basetypes { + /// + /// The representation of a rational number. + /// + public struct Rational { + public static readonly Rational ZERO = Rational.FromInts(0, 1); + public static readonly Rational ONE = Rational.FromInts(1, 1); + public static readonly Rational MINUS_ONE = Rational.FromInts(-1, 1); + + private BigNum numerator, denominator; + + // int numerator; + // int denominator; + + + // invariant: 0 < denominator || (numerator == 0 && denominator == 0); + // invariant: numerator != 0 ==> gcd(abs(numerator),denominator) == 1; + // invariant: numerator == 0 ==> denominator == 1 || denominator == 0; + + public static Rational FromInt(int x) { + return FromBignum(BigNum.FromInt(x)); + } + + public static Rational FromBignum(BigNum n) + { + return new Rational(n, BigNum.ONE); + } + + private Rational(BigNum num, BigNum den) + { + Contract.Assert(den.Signum > 0); + Contract.Assert(num == BigNum.ZERO || num.Gcd(den) == BigNum.ONE); + numerator = num; + denominator = den; + } + + public static Rational FromBignums(BigNum num, BigNum den) { + Contract.Assert(!den.IsZero); + if (num == BigNum.ZERO) + return ZERO; + if (den.Signum < 0) { + den = -den; + num = -num; + } + if (den == BigNum.ONE) + return new Rational(num, den); + var gcd = num.Gcd(den); + if (gcd == BigNum.ONE) + return new Rational(num, den); + return new Rational(num / gcd, den / gcd); + } + + public static Rational FromInts(int num, int den) { + return FromBignums(BigNum.FromInt(num), BigNum.FromInt(den)); + } + + /// + /// Returns the absolute value of the rational. + /// + public Rational Abs() { + Contract.Ensures(Contract.Result().IsNonNegative); + if (IsNonNegative) { + return this; + } else { + return -this; + } + } + + /// + /// Returns a rational whose numerator and denominator, resepctively, are the Gcd + /// of the numerators and denominators of r and s. If one of r and s is 0, the absolute + /// value of the other is returned. If both are 0, 1 is returned. + /// + public static Rational Gcd(Rational r, Rational s) { + Contract.Ensures(Contract.Result().IsPositive); + if (r.IsZero) { + if (s.IsZero) { + return ONE; + } else { + return s.Abs(); + } + } else if (s.IsZero) { + return r.Abs(); + } else { + return new Rational(r.Numerator.Gcd(s.Numerator), + r.Denominator.Gcd(s.Denominator)); + } + } + + public BigNum Numerator { get { return numerator; } } + public BigNum Denominator { get { return denominator == BigNum.ZERO ? BigNum.ONE : denominator; } } + + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + return String.Format("{0}/{1}", Numerator, Denominator); + } + + + public static bool operator ==(Rational r, Rational s) { + return r.Numerator == s.Numerator && r.Denominator == s.Denominator; + } + + public static bool operator !=(Rational r, Rational s) { + return !(r == s); + } + + public override bool Equals(object obj) { + if (obj == null) + return false; + return obj is Rational && (Rational)obj == this; + } + + public override int GetHashCode() { + return this.Numerator.GetHashCode() * 13 + this.Denominator.GetHashCode(); + } + + public int Signum { + get { + return this.Numerator.Signum; + } + } + + public bool IsZero { + get { + return Signum == 0; + } + } + + public bool IsNonZero { + get { + return Signum != 0; + } + } + + public bool IsIntegral { + get { + return Denominator == BigNum.ONE; + } + } + + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public bool HasValue(int n) { + return this == FromInt(n); + } + + /// + /// Returns the rational as an integer. Requires the rational to be integral. + /// + public int AsInteger { + get { + Contract.Assert(this.IsIntegral); + return Numerator.ToIntSafe; + } + } + + public BigNum AsBigNum { + get { + Contract.Assert(this.IsIntegral); + return Numerator; + } + } + + public double AsDouble { + [Pure] + get { + if (this.IsZero) { + return 0.0; + } else { + return (double)Numerator.ToIntSafe / (double)Denominator.ToIntSafe; + } + } + } + + public bool IsNegative { + [Pure] + get { + return Signum < 0; + } + } + + public bool IsPositive { + [Pure] + get { + return 0 < Signum; + } + } + + public bool IsNonNegative { + [Pure] + get { + return 0 <= Signum; + } + } + + public static Rational operator -(Rational r) + { + return new Rational(-r.Numerator, r.Denominator); + } + + public static Rational operator /(Rational r, Rational s) + { + return FromBignums(r.Numerator * s.Denominator, r.Denominator * s.Numerator); + } + + public static Rational operator -(Rational r, Rational s) + { + return r + (-s); + } + + public static Rational operator +(Rational r, Rational s) + { + return FromBignums(r.Numerator * s.Denominator + s.Numerator * r.Denominator, r.Denominator * s.Denominator); + } + + public static Rational operator *(Rational r, Rational s) + { + return FromBignums(r.Numerator * s.Numerator, r.Denominator * s.Denominator); + } + + public static bool operator <(Rational r, Rational s) + { + return (r - s).Signum < 0; + } + + public static bool operator <=(Rational r, Rational s) + { + return !(r > s); + } + + public static bool operator >=(Rational r, Rational s) { + return !(r < s); + } + + public static bool operator >(Rational r, Rational s) { + return s < r; + } + } +} diff --git a/Source/Basetypes/Set.cs b/Source/Basetypes/Set.cs index dfd65b4b..0cc1d103 100644 --- a/Source/Basetypes/Set.cs +++ b/Source/Basetypes/Set.cs @@ -1,286 +1,286 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -namespace Microsoft.Boogie { - using System; - using System.IO; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - - /// - /// A class representing a mathematical set. - /// - public class GSet : ICloneable, IEnumerable, IEnumerable { - /*[Own]*/ - Dictionary ht; - List arr; // keep elements in a well-defined order; otherwise iteration is non-deterministic - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(ht != null); - Contract.Invariant(arr != null); - Contract.Invariant(ht.Count == arr.Count); - } - - - public GSet() { - ht = new Dictionary(); - arr = new List(); - //:base(); - } - - private GSet(Dictionary/*!*/ ht, List arr) { - Contract.Requires(ht != null); - Contract.Requires(arr != null); - this.ht = ht; - this.arr = arr; - //:base(); - } - - public GSet(int capacity) { - ht = new Dictionary(capacity); - arr = new List(capacity); - //:base(); - } - - - public readonly static GSet/*!*/ Empty = new GSet(); - - public void Clear() { - ht.Clear(); - arr.Clear(); - } - - /// - /// This method idempotently adds "o" to the set. - /// In notation: - /// this.SetElements = this.SetElements_old \union {o}; - /// - public void Add(T o) { - if (!ht.ContainsKey(o)) { - ht[o] = arr.Count; - arr.Add(o); - } - } - - /// - /// this.SetElements = this.SetElements_old \union s.GSetElements; - /// - public void AddRange(IEnumerable s) { - foreach (T o in s) { - Add(o); - } - } - - /// - /// this.SetElements = this.SetElements_old \setminus {o}; - /// - public void Remove(T o) { - int idx; - if (ht.TryGetValue(o, out idx)) { - var last = arr[arr.Count - 1]; - arr.RemoveAt(arr.Count - 1); - if (idx != arr.Count) { - arr[idx] = last; - ht[last] = idx; - } - ht.Remove(o); - } - } - - /// - /// this.SetElements = this.SetElements_old \setminus s.SetElements; - /// - public void RemoveRange(IEnumerable s) { - Contract.Requires(s != null); - if (s == this) { - ht.Clear(); - arr.Clear(); - } else { - foreach (T o in s) { - Remove(o); - } - } - } - - /// - /// Returns an arbitrary element from the set. - /// - public T Choose() { - Contract.Requires((Count > 0)); - foreach(var e in this) - return e; - return default(T); - } - - /// - /// Picks an arbitrary element from the set, removes it, and returns it. - /// - public T Take() { - Contract.Requires((Count > 0)); - Contract.Ensures(Count == Contract.OldValue(Count) - 1); - T r = Choose(); - Remove(r); - return r; - } - - public void Intersect(GSet/*!*/ s) { - Contract.Requires(s != null); - if (s == this) return; - ht.Clear(); - var newArr = new List(); - foreach (T key in arr) { - if (s.ht.ContainsKey(key)) { - ht[key] = newArr.Count; - newArr.Add(key); - } - } - arr = newArr; - } - - /// - /// The getter returns true iff "o" is in the set. - /// The setter adds the value "o" (for "true") or removes "o" (for "false") - /// - public bool this[T o] { - get { - return ht.ContainsKey(o); - } - set { - if (value) { - Add(o); - } else { - Remove(o); - } - } - } - - /// - /// Returns true iff "o" is an element of "this". - /// - /// - /// - [Pure] - public bool Contains(T o) { - return this.ht.ContainsKey(o); - } - - /// - /// Returns true iff every element of "s" is an element of "this", that is, if - /// "s" is a subset of "this". - /// - /// - /// - public bool ContainsRange(IEnumerable s) { - Contract.Requires(s != null); - if (s != this) { - foreach (T key in s) { - if (!this.ht.ContainsKey(key)) { - return false; - } - } - } - return true; - } - - public object/*!*/ Clone() { - Contract.Ensures(Contract.Result() != null); - return new GSet(new Dictionary(ht), new List(arr)); - } - - public virtual int Count { - get { - return ht.Count; - } - } - - [Pure] - public override string/*!*/ ToString() { - Contract.Ensures(Contract.Result() != null); - string s = null; - foreach (object/*!*/ key in ht.Keys) { - Contract.Assert(key != null); - if (s == null) { - s = "{"; - } else { - s += ", "; - } - s += key.ToString(); - } - if (s == null) { - return "{}"; - } else { - return s + "}"; - } - } - - //----------------------------- Static Methods --------------------------------- - - // Functional Intersect - public static GSet/*!*/ Intersect(GSet/*!*/ a, GSet/*!*/ b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result>() != null); - //Contract.Ensures(Contract.ForAll(result, x => a[x] && b[x] )); - GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); - res.Intersect(b); - return res; - } - // Functional Union - public static GSet/*!*/ Union(GSet/*!*/ a, GSet/*!*/ b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - Contract.Ensures(Contract.Result>() != null); - // Contract.Ensures(Contract.ForAll(result, x => a[x] || b[x] )); - GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); - res.AddRange(b); - return res; - } - - public delegate bool SetFilter(object/*!*/ obj); - - public static GSet/*!*/ Filter(GSet/*!*/ a, Func filter) { - Contract.Requires(filter != null); - Contract.Requires(a != null); - Contract.Ensures(Contract.Result>() != null); - GSet inter = new GSet(); - - foreach (T elem in a) { - Contract.Assert(elem != null); - if (filter(elem)) { - inter.Add(elem); - } - } - return inter; - } - - public IEnumerator GetEnumerator() - { - return arr.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)arr).GetEnumerator(); - } - - public bool AddAll(IEnumerable s) - { - foreach (T e in s) Add(e); - return true; - } - } - - - public interface IWorkList : ICollection { - bool Add(object o); - bool AddAll(IEnumerable objs); - bool IsEmpty(); - object Pull(); - } - - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.Boogie { + using System; + using System.IO; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + /// + /// A class representing a mathematical set. + /// + public class GSet : ICloneable, IEnumerable, IEnumerable { + /*[Own]*/ + Dictionary ht; + List arr; // keep elements in a well-defined order; otherwise iteration is non-deterministic + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(ht != null); + Contract.Invariant(arr != null); + Contract.Invariant(ht.Count == arr.Count); + } + + + public GSet() { + ht = new Dictionary(); + arr = new List(); + //:base(); + } + + private GSet(Dictionary/*!*/ ht, List arr) { + Contract.Requires(ht != null); + Contract.Requires(arr != null); + this.ht = ht; + this.arr = arr; + //:base(); + } + + public GSet(int capacity) { + ht = new Dictionary(capacity); + arr = new List(capacity); + //:base(); + } + + + public readonly static GSet/*!*/ Empty = new GSet(); + + public void Clear() { + ht.Clear(); + arr.Clear(); + } + + /// + /// This method idempotently adds "o" to the set. + /// In notation: + /// this.SetElements = this.SetElements_old \union {o}; + /// + public void Add(T o) { + if (!ht.ContainsKey(o)) { + ht[o] = arr.Count; + arr.Add(o); + } + } + + /// + /// this.SetElements = this.SetElements_old \union s.GSetElements; + /// + public void AddRange(IEnumerable s) { + foreach (T o in s) { + Add(o); + } + } + + /// + /// this.SetElements = this.SetElements_old \setminus {o}; + /// + public void Remove(T o) { + int idx; + if (ht.TryGetValue(o, out idx)) { + var last = arr[arr.Count - 1]; + arr.RemoveAt(arr.Count - 1); + if (idx != arr.Count) { + arr[idx] = last; + ht[last] = idx; + } + ht.Remove(o); + } + } + + /// + /// this.SetElements = this.SetElements_old \setminus s.SetElements; + /// + public void RemoveRange(IEnumerable s) { + Contract.Requires(s != null); + if (s == this) { + ht.Clear(); + arr.Clear(); + } else { + foreach (T o in s) { + Remove(o); + } + } + } + + /// + /// Returns an arbitrary element from the set. + /// + public T Choose() { + Contract.Requires((Count > 0)); + foreach(var e in this) + return e; + return default(T); + } + + /// + /// Picks an arbitrary element from the set, removes it, and returns it. + /// + public T Take() { + Contract.Requires((Count > 0)); + Contract.Ensures(Count == Contract.OldValue(Count) - 1); + T r = Choose(); + Remove(r); + return r; + } + + public void Intersect(GSet/*!*/ s) { + Contract.Requires(s != null); + if (s == this) return; + ht.Clear(); + var newArr = new List(); + foreach (T key in arr) { + if (s.ht.ContainsKey(key)) { + ht[key] = newArr.Count; + newArr.Add(key); + } + } + arr = newArr; + } + + /// + /// The getter returns true iff "o" is in the set. + /// The setter adds the value "o" (for "true") or removes "o" (for "false") + /// + public bool this[T o] { + get { + return ht.ContainsKey(o); + } + set { + if (value) { + Add(o); + } else { + Remove(o); + } + } + } + + /// + /// Returns true iff "o" is an element of "this". + /// + /// + /// + [Pure] + public bool Contains(T o) { + return this.ht.ContainsKey(o); + } + + /// + /// Returns true iff every element of "s" is an element of "this", that is, if + /// "s" is a subset of "this". + /// + /// + /// + public bool ContainsRange(IEnumerable s) { + Contract.Requires(s != null); + if (s != this) { + foreach (T key in s) { + if (!this.ht.ContainsKey(key)) { + return false; + } + } + } + return true; + } + + public object/*!*/ Clone() { + Contract.Ensures(Contract.Result() != null); + return new GSet(new Dictionary(ht), new List(arr)); + } + + public virtual int Count { + get { + return ht.Count; + } + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result() != null); + string s = null; + foreach (object/*!*/ key in ht.Keys) { + Contract.Assert(key != null); + if (s == null) { + s = "{"; + } else { + s += ", "; + } + s += key.ToString(); + } + if (s == null) { + return "{}"; + } else { + return s + "}"; + } + } + + //----------------------------- Static Methods --------------------------------- + + // Functional Intersect + public static GSet/*!*/ Intersect(GSet/*!*/ a, GSet/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result>() != null); + //Contract.Ensures(Contract.ForAll(result, x => a[x] && b[x] )); + GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); + res.Intersect(b); + return res; + } + // Functional Union + public static GSet/*!*/ Union(GSet/*!*/ a, GSet/*!*/ b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result>() != null); + // Contract.Ensures(Contract.ForAll(result, x => a[x] || b[x] )); + GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); + res.AddRange(b); + return res; + } + + public delegate bool SetFilter(object/*!*/ obj); + + public static GSet/*!*/ Filter(GSet/*!*/ a, Func filter) { + Contract.Requires(filter != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result>() != null); + GSet inter = new GSet(); + + foreach (T elem in a) { + Contract.Assert(elem != null); + if (filter(elem)) { + inter.Add(elem); + } + } + return inter; + } + + public IEnumerator GetEnumerator() + { + return arr.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)arr).GetEnumerator(); + } + + public bool AddAll(IEnumerable s) + { + foreach (T e in s) Add(e); + return true; + } + } + + + public interface IWorkList : ICollection { + bool Add(object o); + bool AddAll(IEnumerable objs); + bool IsEmpty(); + object Pull(); + } + + } \ No newline at end of file diff --git a/Source/Basetypes/cce.cs b/Source/Basetypes/cce.cs index ef594484..1e0b12a5 100644 --- a/Source/Basetypes/cce.cs +++ b/Source/Basetypes/cce.cs @@ -1,193 +1,193 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); - } - //[Pure] - //public static bool NonNullElements(VariableSeq collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) { - return iEnumerator != null; - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - //[Pure] - //public static bool IsValid(Microsoft.Dafny.Expression expression) { - // return true; - //} - //public static List toList(PureCollections.Sequence s) { - // List toRet = new List(); - // foreach (T t in s.elems) - // if(t!=null) - // toRet.Add(t); - // return toRet; - //} - - //internal static bool NonNullElements(Set set) { - // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); - //} -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { +using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// +/// A class containing static methods to extend the functionality of Code Contracts +/// + +public static class cce { + //[Pure] + //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(IDictionary collection) { + return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); + } + //[Pure] + //public static bool NonNullElements(VariableSeq collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// + /// For possibly-null lists of non-null elements + /// + /// + /// + /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! + /// + [Pure] + public static bool NonNullElements(IEnumerable collection, bool nullability) { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements(KeyValuePair kvp) { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements(IEnumerator iEnumerator) { + return iEnumerator != null; + } + //[Pure] + //public static bool NonNullElements(Graphing.Graph graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + //[Pure] + //public static bool IsValid(Microsoft.Dafny.Expression expression) { + // return true; + //} + //public static List toList(PureCollections.Sequence s) { + // List toRet = new List(); + // foreach (T t in s.elems) + // if(t!=null) + // toRet.Add(t); + // return toRet; + //} + + //internal static bool NonNullElements(Set set) { + // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); + //} +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { } \ No newline at end of file diff --git a/Source/Boogie.sln b/Source/Boogie.sln index f16c1032..0823775c 100644 --- a/Source/Boogie.sln +++ b/Source/Boogie.sln @@ -1,643 +1,643 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Provers", "Provers", "{B758C1E3-824A-439F-AA2F-0BA1143E8C8D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoogieDriver", "BoogieDriver\BoogieDriver.csproj", "{DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}" - ProjectSection(ProjectDependencies) = postProject - {D07B8E38-E172-47F4-AD02-0373014A46D3} = {D07B8E38-E172-47F4-AD02-0373014A46D3} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbsInt", "AbsInt\AbsInt.csproj", "{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMTLib", "Provers\SMTLib\SMTLib.csproj", "{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCGeneration", "VCGeneration\VCGeneration.csproj", "{E1F10180-C7B9-4147-B51F-FA1B701966DC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csproj", "{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B230A69C-C466-4065-B9C1-84D80E76D802}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Graph", "Graph\Graph.csproj", "{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Basetypes", "Basetypes\Basetypes.csproj", "{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeContractsExtender", "CodeContractsExtender\CodeContractsExtender.csproj", "{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelViewer", "ModelViewer\ModelViewer.csproj", "{A678C6EB-B329-46A9-BBFC-7585F01ACD7C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserHelper", "ParserHelper\ParserHelper.csproj", "{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Predication", "Predication\Predication.csproj", "{AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doomed", "Doomed\Doomed.csproj", "{884386A3-58E9-40BB-A273-B24976775553}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionEngine", "ExecutionEngine\ExecutionEngine.csproj", "{EAA5EB79-D475-4601-A59B-825C191CD25F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BVD", "BVD\BVD.csproj", "{8A05D14E-F2BF-4890-BBE0-D76B18A50797}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Concurrency", "Concurrency\Concurrency.csproj", "{D07B8E38-E172-47F4-AD02-0373014A46D3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0C77D814-EC94-45D7-9F9B-213C425D0F15}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreTests", "UnitTests\CoreTests\CoreTests.csproj", "{961B3BCA-2067-43B2-8E43-23C4293F21B9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtil", "UnitTests\TestUtil\TestUtil.csproj", "{59118E35-4236-495E-AF6E-0D641302ED2C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasetypesTests", "UnitTests\BasetypesTests\BasetypesTests.csproj", "{D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Checked|.NET = Checked|.NET - Checked|Any CPU = Checked|Any CPU - Checked|Mixed Platforms = Checked|Mixed Platforms - Checked|x86 = Checked|x86 - Debug|.NET = Debug|.NET - Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x86 = Debug|x86 - Release|.NET = Release|.NET - Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|x86 = Release|x86 - z3apidebug|.NET = z3apidebug|.NET - z3apidebug|Any CPU = z3apidebug|Any CPU - z3apidebug|Mixed Platforms = z3apidebug|Mixed Platforms - z3apidebug|x86 = z3apidebug|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.Build.0 = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.Build.0 = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|x86.ActiveCfg = Checked|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|x86.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.Build.0 = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.Build.0 = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|x86.ActiveCfg = Release|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.Build.0 = z3apidebug|x86 - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.Build.0 = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.Build.0 = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|x86.ActiveCfg = Checked|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|x86.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.Build.0 = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.Build.0 = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|x86.ActiveCfg = Release|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.Build.0 = z3apidebug|x86 - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.Build.0 = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.Build.0 = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|x86.ActiveCfg = Checked|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|x86.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|.NET.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.Build.0 = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|x86.ActiveCfg = Release|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.Build.0 = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.Build.0 = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|x86.ActiveCfg = Checked|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|x86.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|.NET.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.Build.0 = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|x86.ActiveCfg = Release|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.Build.0 = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.Build.0 = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|x86.ActiveCfg = Checked|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|x86.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|.NET.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.Build.0 = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|x86.ActiveCfg = Release|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.Build.0 = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.Build.0 = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|x86.ActiveCfg = Checked|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|x86.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.Build.0 = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.Build.0 = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|x86.ActiveCfg = Release|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.Build.0 = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.Build.0 = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|x86.ActiveCfg = Checked|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|x86.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|.NET.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.Build.0 = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|x86.ActiveCfg = Release|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.Build.0 = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.Build.0 = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|x86.ActiveCfg = Checked|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|x86.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.Build.0 = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.Build.0 = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|x86.ActiveCfg = Release|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.Build.0 = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.Build.0 = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|x86.ActiveCfg = Checked|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|x86.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.Build.0 = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.Build.0 = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|x86.ActiveCfg = Release|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.Build.0 = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Any CPU.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.Build.0 = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.ActiveCfg = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.Build.0 = Checked|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.Build.0 = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Any CPU.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.ActiveCfg = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.Build.0 = Debug|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|.NET.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Any CPU.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.Build.0 = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.Build.0 = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|.NET.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Any CPU.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.Build.0 = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.ActiveCfg = Release|x86 - {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.Build.0 = Release|x86 - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.Build.0 = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.Build.0 = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|x86.ActiveCfg = Checked|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.Build.0 = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|x86.ActiveCfg = Debug|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|.NET.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|x86.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.Build.0 = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.Build.0 = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|x86.ActiveCfg = Checked|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.Build.0 = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|x86.ActiveCfg = Debug|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|.NET.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|x86.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|x86.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|x86.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|.NET.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|x86.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|x86.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|x86.ActiveCfg = Debug|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|.NET.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|x86.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Checked|x86.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Debug|x86.ActiveCfg = Debug|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.Release|x86.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|x86.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|x86.ActiveCfg = Debug|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|.NET.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|x86.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|x86.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|x86.ActiveCfg = Debug|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|x86.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|x86.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|x86.ActiveCfg = Debug|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|x86.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|.NET.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|x86.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|.NET.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|x86.ActiveCfg = Debug|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|.NET.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|x86.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|.NET.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|x86.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|.NET.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|x86.ActiveCfg = Debug|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|.NET.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|x86.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|x86.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|.NET.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|x86.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|.NET.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|x86.ActiveCfg = Debug|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|.NET.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|x86.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D} - {961B3BCA-2067-43B2-8E43-23C4293F21B9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} - {59118E35-4236-495E-AF6E-0D641302ED2C} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} - {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Provers", "Provers", "{B758C1E3-824A-439F-AA2F-0BA1143E8C8D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoogieDriver", "BoogieDriver\BoogieDriver.csproj", "{DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}" + ProjectSection(ProjectDependencies) = postProject + {D07B8E38-E172-47F4-AD02-0373014A46D3} = {D07B8E38-E172-47F4-AD02-0373014A46D3} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbsInt", "AbsInt\AbsInt.csproj", "{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMTLib", "Provers\SMTLib\SMTLib.csproj", "{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCGeneration", "VCGeneration\VCGeneration.csproj", "{E1F10180-C7B9-4147-B51F-FA1B701966DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csproj", "{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B230A69C-C466-4065-B9C1-84D80E76D802}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Graph", "Graph\Graph.csproj", "{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Basetypes", "Basetypes\Basetypes.csproj", "{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeContractsExtender", "CodeContractsExtender\CodeContractsExtender.csproj", "{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelViewer", "ModelViewer\ModelViewer.csproj", "{A678C6EB-B329-46A9-BBFC-7585F01ACD7C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserHelper", "ParserHelper\ParserHelper.csproj", "{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Predication", "Predication\Predication.csproj", "{AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doomed", "Doomed\Doomed.csproj", "{884386A3-58E9-40BB-A273-B24976775553}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionEngine", "ExecutionEngine\ExecutionEngine.csproj", "{EAA5EB79-D475-4601-A59B-825C191CD25F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BVD", "BVD\BVD.csproj", "{8A05D14E-F2BF-4890-BBE0-D76B18A50797}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Concurrency", "Concurrency\Concurrency.csproj", "{D07B8E38-E172-47F4-AD02-0373014A46D3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0C77D814-EC94-45D7-9F9B-213C425D0F15}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreTests", "UnitTests\CoreTests\CoreTests.csproj", "{961B3BCA-2067-43B2-8E43-23C4293F21B9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtil", "UnitTests\TestUtil\TestUtil.csproj", "{59118E35-4236-495E-AF6E-0D641302ED2C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasetypesTests", "UnitTests\BasetypesTests\BasetypesTests.csproj", "{D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|.NET = Checked|.NET + Checked|Any CPU = Checked|Any CPU + Checked|Mixed Platforms = Checked|Mixed Platforms + Checked|x86 = Checked|x86 + Debug|.NET = Debug|.NET + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|.NET = Release|.NET + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + z3apidebug|.NET = z3apidebug|.NET + z3apidebug|Any CPU = z3apidebug|Any CPU + z3apidebug|Mixed Platforms = z3apidebug|Mixed Platforms + z3apidebug|x86 = z3apidebug|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|.NET.Build.0 = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Any CPU.Build.0 = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Checked|x86.ActiveCfg = Checked|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|.NET.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Debug|x86.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|.NET.Build.0 = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Any CPU.Build.0 = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.Release|x86.ActiveCfg = Release|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}.z3apidebug|x86.Build.0 = z3apidebug|x86 + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|.NET.Build.0 = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Any CPU.Build.0 = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Checked|x86.ActiveCfg = Checked|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|.NET.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Debug|x86.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|.NET.Build.0 = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Any CPU.Build.0 = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.Release|x86.ActiveCfg = Release|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.ActiveCfg = z3apidebug|x86 + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.Build.0 = z3apidebug|x86 + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.Build.0 = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.Build.0 = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|x86.ActiveCfg = Checked|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|.NET.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Debug|x86.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|.NET.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Any CPU.Build.0 = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Release|x86.ActiveCfg = Release|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.Build.0 = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.Build.0 = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|x86.ActiveCfg = Checked|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|.NET.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Debug|x86.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|.NET.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Any CPU.Build.0 = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.Release|x86.ActiveCfg = Release|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {E1F10180-C7B9-4147-B51F-FA1B701966DC}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|.NET.Build.0 = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Any CPU.Build.0 = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Checked|x86.ActiveCfg = Checked|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|.NET.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Debug|x86.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|.NET.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Any CPU.Build.0 = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.Release|x86.ActiveCfg = Release|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|.NET.Build.0 = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Any CPU.Build.0 = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Checked|x86.ActiveCfg = Checked|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|.NET.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Debug|x86.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|.NET.Build.0 = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Any CPU.Build.0 = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.Release|x86.ActiveCfg = Release|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.Build.0 = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.Build.0 = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|x86.ActiveCfg = Checked|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|.NET.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Debug|x86.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|.NET.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Any CPU.Build.0 = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Release|x86.ActiveCfg = Release|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|.NET.Build.0 = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Any CPU.Build.0 = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Checked|x86.ActiveCfg = Checked|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|.NET.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Debug|x86.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|.NET.Build.0 = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Any CPU.Build.0 = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.Release|x86.ActiveCfg = Release|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|.NET.Build.0 = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Any CPU.Build.0 = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Checked|x86.ActiveCfg = Checked|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|.NET.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Debug|x86.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|.NET.Build.0 = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Any CPU.Build.0 = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.Release|x86.ActiveCfg = Release|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|.NET.Build.0 = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Any CPU.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|Mixed Platforms.Build.0 = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.ActiveCfg = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Checked|x86.Build.0 = Checked|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|.NET.Build.0 = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Any CPU.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.ActiveCfg = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Debug|x86.Build.0 = Debug|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|.NET.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Any CPU.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|Mixed Platforms.Build.0 = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.Release|x86.Build.0 = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|.NET.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Any CPU.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|Mixed Platforms.Build.0 = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.ActiveCfg = Release|x86 + {A678C6EB-B329-46A9-BBFC-7585F01ACD7C}.z3apidebug|x86.Build.0 = Release|x86 + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|.NET.Build.0 = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Any CPU.Build.0 = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Checked|x86.ActiveCfg = Checked|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|.NET.Build.0 = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Debug|x86.ActiveCfg = Debug|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|.NET.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Any CPU.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.Release|x86.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}.z3apidebug|x86.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|.NET.Build.0 = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Any CPU.Build.0 = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Checked|x86.ActiveCfg = Checked|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|.NET.Build.0 = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Debug|x86.ActiveCfg = Debug|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|.NET.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Any CPU.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.Release|x86.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|x86.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|.NET.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|.NET.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Any CPU.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Release|x86.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|x86.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|x86.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|x86.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|x86.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|.NET.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Any CPU.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Checked|x86.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|.NET.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Debug|x86.ActiveCfg = Debug|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|.NET.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Any CPU.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.Release|x86.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {EAA5EB79-D475-4601-A59B-825C191CD25F}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|.NET.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Any CPU.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Checked|x86.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|.NET.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Debug|x86.ActiveCfg = Debug|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|.NET.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Any CPU.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.Release|x86.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {8A05D14E-F2BF-4890-BBE0-D76B18A50797}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|.NET.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Any CPU.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Checked|x86.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|.NET.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Debug|x86.ActiveCfg = Debug|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|.NET.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Any CPU.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.Release|x86.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {D07B8E38-E172-47F4-AD02-0373014A46D3}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|.NET.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Any CPU.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Checked|x86.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|.NET.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Debug|x86.ActiveCfg = Debug|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|.NET.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Any CPU.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.Release|x86.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {961B3BCA-2067-43B2-8E43-23C4293F21B9}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|.NET.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Any CPU.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Checked|x86.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|.NET.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|.NET.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Any CPU.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.Release|x86.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {59118E35-4236-495E-AF6E-0D641302ED2C}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|.NET.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Any CPU.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|Mixed Platforms.Build.0 = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Checked|x86.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|.NET.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Debug|x86.ActiveCfg = Debug|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|.NET.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Any CPU.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.Release|x86.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9}.z3apidebug|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D} + {961B3BCA-2067-43B2-8E43-23C4293F21B9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} + {59118E35-4236-495E-AF6E-0D641302ED2C} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} + {D00C3F22-1EDA-4781-8F0E-81991E9CB0D9} = {0C77D814-EC94-45D7-9F9B-213C425D0F15} + EndGlobalSection +EndGlobal diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs index cba74bc5..be88a745 100644 --- a/Source/BoogieDriver/BoogieDriver.cs +++ b/Source/BoogieDriver/BoogieDriver.cs @@ -1,106 +1,106 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// OnlyBoogie OnlyBoogie.ssc -// - main program for taking a BPL program and verifying it -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.IO; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - - /* - The following assemblies are referenced because they are needed at runtime, not at compile time: - BaseTypes - Provers.Z3 - System.Compiler.Framework - */ - - public class OnlyBoogie - { - - public static int Main(string[] args) - { - Contract.Requires(cce.NonNullElements(args)); - - ExecutionEngine.printer = new ConsolePrinter(); - - CommandLineOptions.Install(new CommandLineOptions()); - - CommandLineOptions.Clo.RunningBoogieFromCommandLine = true; - if (!CommandLineOptions.Clo.Parse(args)) { - goto END; - } - if (CommandLineOptions.Clo.Files.Count == 0) { - ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: No input files were specified."); - goto END; - } - if (CommandLineOptions.Clo.XmlSink != null) { - string errMsg = CommandLineOptions.Clo.XmlSink.Open(); - if (errMsg != null) { - ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: " + errMsg); - goto END; - } - } - if (!CommandLineOptions.Clo.DontShowLogo) { - Console.WriteLine(CommandLineOptions.Clo.Version); - } - if (CommandLineOptions.Clo.ShowEnv == CommandLineOptions.ShowEnvironment.Always) { - Console.WriteLine("---Command arguments"); - foreach (string arg in args) { - Contract.Assert(arg != null); - Console.WriteLine(arg); - } - - Console.WriteLine("--------------------"); - } - - Helpers.ExtraTraceInformation("Becoming sentient"); - - List fileList = new List(); - foreach (string file in CommandLineOptions.Clo.Files) { - string extension = Path.GetExtension(file); - if (extension != null) { - extension = extension.ToLower(); - } - if (extension == ".txt") { - StreamReader stream = new StreamReader(file); - string s = stream.ReadToEnd(); - fileList.AddRange(s.Split(new char[3] {' ', '\n', '\r'}, StringSplitOptions.RemoveEmptyEntries)); - } - else { - fileList.Add(file); - } - } - foreach (string file in fileList) { - Contract.Assert(file != null); - string extension = Path.GetExtension(file); - if (extension != null) { - extension = extension.ToLower(); - } - if (extension != ".bpl") { - ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be BoogiePL programs (.bpl).", file, - extension == null ? "" : extension); - goto END; - } - } - ExecutionEngine.ProcessFiles(fileList); - return 0; - - END: - if (CommandLineOptions.Clo.XmlSink != null) { - CommandLineOptions.Clo.XmlSink.Close(); - } - if (CommandLineOptions.Clo.Wait) { - Console.WriteLine("Press Enter to exit."); - Console.ReadLine(); - } - return 1; - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// OnlyBoogie OnlyBoogie.ssc +// - main program for taking a BPL program and verifying it +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.IO; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + /* + The following assemblies are referenced because they are needed at runtime, not at compile time: + BaseTypes + Provers.Z3 + System.Compiler.Framework + */ + + public class OnlyBoogie + { + + public static int Main(string[] args) + { + Contract.Requires(cce.NonNullElements(args)); + + ExecutionEngine.printer = new ConsolePrinter(); + + CommandLineOptions.Install(new CommandLineOptions()); + + CommandLineOptions.Clo.RunningBoogieFromCommandLine = true; + if (!CommandLineOptions.Clo.Parse(args)) { + goto END; + } + if (CommandLineOptions.Clo.Files.Count == 0) { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: No input files were specified."); + goto END; + } + if (CommandLineOptions.Clo.XmlSink != null) { + string errMsg = CommandLineOptions.Clo.XmlSink.Open(); + if (errMsg != null) { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: " + errMsg); + goto END; + } + } + if (!CommandLineOptions.Clo.DontShowLogo) { + Console.WriteLine(CommandLineOptions.Clo.Version); + } + if (CommandLineOptions.Clo.ShowEnv == CommandLineOptions.ShowEnvironment.Always) { + Console.WriteLine("---Command arguments"); + foreach (string arg in args) { + Contract.Assert(arg != null); + Console.WriteLine(arg); + } + + Console.WriteLine("--------------------"); + } + + Helpers.ExtraTraceInformation("Becoming sentient"); + + List fileList = new List(); + foreach (string file in CommandLineOptions.Clo.Files) { + string extension = Path.GetExtension(file); + if (extension != null) { + extension = extension.ToLower(); + } + if (extension == ".txt") { + StreamReader stream = new StreamReader(file); + string s = stream.ReadToEnd(); + fileList.AddRange(s.Split(new char[3] {' ', '\n', '\r'}, StringSplitOptions.RemoveEmptyEntries)); + } + else { + fileList.Add(file); + } + } + foreach (string file in fileList) { + Contract.Assert(file != null); + string extension = Path.GetExtension(file); + if (extension != null) { + extension = extension.ToLower(); + } + if (extension != ".bpl") { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be BoogiePL programs (.bpl).", file, + extension == null ? "" : extension); + goto END; + } + } + ExecutionEngine.ProcessFiles(fileList); + return 0; + + END: + if (CommandLineOptions.Clo.XmlSink != null) { + CommandLineOptions.Clo.XmlSink.Close(); + } + if (CommandLineOptions.Clo.Wait) { + Console.WriteLine("Press Enter to exit."); + Console.ReadLine(); + } + return 1; + } + } +} diff --git a/Source/BoogieDriver/BoogieDriver.csproj b/Source/BoogieDriver/BoogieDriver.csproj index 14d607f9..90e0be41 100644 --- a/Source/BoogieDriver/BoogieDriver.csproj +++ b/Source/BoogieDriver/BoogieDriver.csproj @@ -1,324 +1,324 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A} - Exe - Properties - BoogieDriver - Boogie - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - false - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - true - full - false - ..\..\Binaries\ - TRACE;DEBUG - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - ..\..\Binaries\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - ..\Provers\Z3api\bin\z3apidebug\ - DEBUG;TRACE - full - x86 - - - true - GlobalSuppressions.cs - prompt - Migrated rules for BoogieDriver.ruleset - true - 4 - false - - - true - ..\..\Binaries\ - DEBUG;TRACE - full - AnyCPU - ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\x86\Debug\ - TRACE;DEBUG - full - x86 - ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - 4 - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - bin\Release\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - 4 - - - true - bin\x86\z3apidebug\ - DEBUG;TRACE - full - x86 - bin\z3apidebug\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - Migrated rules for BoogieDriver.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - true - 4 - false - - - true - bin\x86\Checked\ - DEBUG;TRACE - full - x86 - ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - 4 - false - - - true - bin\QED\ - TRACE;DEBUG - full - AnyCPU - prompt - AllRules.ruleset - - - true - ..\..\Binaries\ - TRACE;DEBUG - full - AnyCPU - prompt - AllRules.ruleset - false - - - - - - - - - - - - - {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} - AbsInt - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {884386A3-58E9-40BB-A273-B24976775553} - Doomed - - - {EAA5EB79-D475-4601-A59B-825C191CD25F} - ExecutionEngine - - - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} - Graph - - - {CF41E903-78EB-43BA-A355-E5FEB5ECECD4} - Houdini - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44} - Predication - - - {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} - SMTLib - - - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} - VCExpr - - - {E1F10180-C7B9-4147-B51F-FA1B701966DC} - VCGeneration - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A} + Exe + Properties + BoogieDriver + Boogie + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + false + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + ..\..\Binaries\ + TRACE;DEBUG + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + ..\..\Binaries\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + ..\Provers\Z3api\bin\z3apidebug\ + DEBUG;TRACE + full + x86 + + + true + GlobalSuppressions.cs + prompt + Migrated rules for BoogieDriver.ruleset + true + 4 + false + + + true + ..\..\Binaries\ + DEBUG;TRACE + full + AnyCPU + ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\x86\Debug\ + TRACE;DEBUG + full + x86 + ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + 4 + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + bin\Release\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + 4 + + + true + bin\x86\z3apidebug\ + DEBUG;TRACE + full + x86 + bin\z3apidebug\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + Migrated rules for BoogieDriver.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + true + 4 + false + + + true + bin\x86\Checked\ + DEBUG;TRACE + full + x86 + ..\..\Binaries\Boogie.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + 4 + false + + + true + bin\QED\ + TRACE;DEBUG + full + AnyCPU + prompt + AllRules.ruleset + + + true + ..\..\Binaries\ + TRACE;DEBUG + full + AnyCPU + prompt + AllRules.ruleset + false + + + + + + + + + + + + + {0EFA3E43-690B-48DC-A72C-384A3EA7F31F} + AbsInt + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + {B230A69C-C466-4065-B9C1-84D80E76D802} + Core + + + {884386A3-58E9-40BB-A273-B24976775553} + Doomed + + + {EAA5EB79-D475-4601-A59B-825C191CD25F} + ExecutionEngine + + + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} + Graph + + + {CF41E903-78EB-43BA-A355-E5FEB5ECECD4} + Houdini + + + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} + ParserHelper + + + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44} + Predication + + + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} + SMTLib + + + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} + VCExpr + + + {E1F10180-C7B9-4147-B51F-FA1B701966DC} + VCGeneration + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Source/BoogieDriver/cce.cs b/Source/BoogieDriver/cce.cs index 23d79815..42cabfcb 100644 --- a/Source/BoogieDriver/cce.cs +++ b/Source/BoogieDriver/cce.cs @@ -1,105 +1,105 @@ - -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -using Microsoft.Boogie; - - /// - /// A class containing static methods to extend the functionality of Code Contracts - /// - -public static class cce { - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values); - } - [Pure] - public static bool NonNullElements(VariableSeq collection) { - return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - } - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - - public class UnreachableException : Exception { - public UnreachableException() { - } - } -} - -public class PeerAttribute : System.Attribute { -} -public class RepAttribute : System.Attribute { -} -public class CapturedAttribute : System.Attribute { -} -public class NotDelayedAttribute : System.Attribute { -} -public class NoDefaultContractAttribute : System.Attribute { -} -public class VerifyAttribute : System.Attribute { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : System.Attribute { - } -public class AdditiveAttribute : System.Attribute { -} -public class ReadsAttribute : System.Attribute { - public enum Reads { - Nothing, - }; - public ReadsAttribute(object o) { - } -} + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +using Microsoft.Boogie; + + /// + /// A class containing static methods to extend the functionality of Code Contracts + /// + +public static class cce { + [Pure] + public static T NonNull(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements(IDictionary collection) { + return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values); + } + [Pure] + public static bool NonNullElements(VariableSeq collection) { + return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + } + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + + public class UnreachableException : Exception { + public UnreachableException() { + } + } +} + +public class PeerAttribute : System.Attribute { +} +public class RepAttribute : System.Attribute { +} +public class CapturedAttribute : System.Attribute { +} +public class NotDelayedAttribute : System.Attribute { +} +public class NoDefaultContractAttribute : System.Attribute { +} +public class VerifyAttribute : System.Attribute { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : System.Attribute { + } +public class AdditiveAttribute : System.Attribute { +} +public class ReadsAttribute : System.Attribute { + public enum Reads { + Nothing, + }; + public ReadsAttribute(object o) { + } +} diff --git a/Source/CodeContractsExtender/CodeContractsExtender.csproj b/Source/CodeContractsExtender/CodeContractsExtender.csproj index c87ed8ab..05701c12 100644 --- a/Source/CodeContractsExtender/CodeContractsExtender.csproj +++ b/Source/CodeContractsExtender/CodeContractsExtender.csproj @@ -1,202 +1,202 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - Library - Properties - CodeContractsExtender - CodeContractsExtender - v4.0 - 512 - true - ..\InterimKey.snk - 1 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for CodeContractsExtender.ruleset - true - 4 - false - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\CodeContractsExtender.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - 4 - false - - - true - bin\QED\ - DEBUG;TRACE - full - AnyCPU - prompt - AllRules.ruleset - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - version.cs - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + Library + Properties + CodeContractsExtender + CodeContractsExtender + v4.0 + 512 + true + ..\InterimKey.snk + 1 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for CodeContractsExtender.ruleset + true + 4 + false + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\CodeContractsExtender.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + 4 + false + + + true + bin\QED\ + DEBUG;TRACE + full + AnyCPU + prompt + AllRules.ruleset + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + version.cs + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + diff --git a/Source/CodeContractsExtender/cce.cs b/Source/CodeContractsExtender/cce.cs index 02b80458..0e6a0607 100644 --- a/Source/CodeContractsExtender/cce.cs +++ b/Source/CodeContractsExtender/cce.cs @@ -1,184 +1,184 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) where T : class { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) where T : class { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullDictionaryAndValues(IDictionary collection) where TValue : class { - return collection != null && cce.NonNullElements(collection.Values); - } - //[Pure] - //public static bool NonNullElements(List collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) where T : class { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) where TKey : class where TValue : class { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) where T : class { - return iEnumerator != null; - } - [Pure] - public static bool NonNull(HashSet set) where T : class { - return set != null && !set.Contains(null); - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { +using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// +/// A class containing static methods to extend the functionality of Code Contracts +/// + +public static class cce { + //[Pure] + //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull(T t) where T : class { + Contract.Requires(t != null); + Contract.Ensures(Contract.Result() != null); + return t; + } + [Pure] + public static bool NonNullElements(IEnumerable collection) where T : class { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullDictionaryAndValues(IDictionary collection) where TValue : class { + return collection != null && cce.NonNullElements(collection.Values); + } + //[Pure] + //public static bool NonNullElements(List collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// + /// For possibly-null lists of non-null elements + /// + /// + /// + /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! + /// + [Pure] + public static bool NonNullElements(IEnumerable collection, bool nullability) where T : class { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements(KeyValuePair kvp) where TKey : class where TValue : class { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements(IEnumerator iEnumerator) where T : class { + return iEnumerator != null; + } + [Pure] + public static bool NonNull(HashSet set) where T : class { + return set != null && !set.Contains(null); + } + //[Pure] + //public static bool NonNullElements(Graphing.Graph graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { } \ No newline at end of file diff --git a/Source/Concurrency/App.config b/Source/Concurrency/App.config index 84bc4207..e95ce985 100644 --- a/Source/Concurrency/App.config +++ b/Source/Concurrency/App.config @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/Source/Concurrency/Concurrency.csproj b/Source/Concurrency/Concurrency.csproj index c245d05a..f15ebca3 100644 --- a/Source/Concurrency/Concurrency.csproj +++ b/Source/Concurrency/Concurrency.csproj @@ -1,115 +1,115 @@ - - - - - Debug - AnyCPU - {D07B8E38-E172-47F4-AD02-0373014A46D3} - Library - Properties - Concurrency - Concurrency - v4.0 - 512 - Client - - - AnyCPU - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - true - - - ..\InterimKey.snk - - - true - bin\QED\ - TRACE;DEBUG;QED - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - ..\..\Binaries\Microsoft.Automata.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {43dfad18-3e35-4558-9be2-caff6b5ba8a0} - Basetypes - - - {b230a69c-c466-4065-b9c1-84d80e76d802} - Core - - - {69a2b0b8-bcac-4101-ae7a-556fcc58c06e} - Graph - - - {fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5} - ParserHelper - - - - - - - + + + + + Debug + AnyCPU + {D07B8E38-E172-47F4-AD02-0373014A46D3} + Library + Properties + Concurrency + Concurrency + v4.0 + 512 + Client + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + true + + + ..\InterimKey.snk + + + true + bin\QED\ + TRACE;DEBUG;QED + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + + + ..\..\Binaries\Microsoft.Automata.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {43dfad18-3e35-4558-9be2-caff6b5ba8a0} + Basetypes + + + {b230a69c-c466-4065-b9c1-84d80e76d802} + Core + + + {69a2b0b8-bcac-4101-ae7a-556fcc58c06e} + Graph + + + {fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5} + ParserHelper + + + + + + + \ No newline at end of file diff --git a/Source/Concurrency/LinearSets.cs b/Source/Concurrency/LinearSets.cs index e3891c18..0fa04b1b 100644 --- a/Source/Concurrency/LinearSets.cs +++ b/Source/Concurrency/LinearSets.cs @@ -1,1004 +1,1004 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Boogie; -using System.Diagnostics; - -namespace Microsoft.Boogie -{ - public class LinearEraser : ReadOnlyVisitor - { - private QKeyValue RemoveLinearAttribute(QKeyValue iter) - { - if (iter == null) return null; - iter.Next = RemoveLinearAttribute(iter.Next); - return (iter.Key == "linear" || iter.Key == "linear_in" || iter.Key == "linear_out") ? iter.Next : iter; - } - - public override Variable VisitVariable(Variable node) - { - node.Attributes = RemoveLinearAttribute(node.Attributes); - return base.VisitVariable(node); - } - - public override Function VisitFunction(Function node) - { - node.Attributes = RemoveLinearAttribute(node.Attributes); - return base.VisitFunction(node); - } - } - - public enum LinearKind { - LINEAR, - LINEAR_IN, - LINEAR_OUT - } - - public class LinearTypeChecker : ReadOnlyVisitor - { - public Program program; - public int errorCount; - public CheckingContext checkingContext; - public Dictionary> domainNameToCollectors; - private Dictionary> availableLinearVars; - public Dictionary inParamToLinearQualifier; - public Dictionary outParamToDomainName; - public Dictionary varToDomainName; - public Dictionary globalVarToDomainName; - public Dictionary linearDomains; - - public LinearTypeChecker(Program program) - { - this.program = program; - this.errorCount = 0; - this.checkingContext = new CheckingContext(null); - this.domainNameToCollectors = new Dictionary>(); - this.availableLinearVars = new Dictionary>(); - this.inParamToLinearQualifier = new Dictionary(); - this.outParamToDomainName = new Dictionary(); - this.varToDomainName = new Dictionary(); - this.globalVarToDomainName = new Dictionary(); - this.linearDomains = new Dictionary(); - } - public void TypeCheck() - { - this.VisitProgram(program); - foreach (string domainName in domainNameToCollectors.Keys) - { - var collectors = domainNameToCollectors[domainName]; - if (collectors.Count == 0) continue; - this.linearDomains[domainName] = new LinearDomain(program, domainName, collectors); - } - Dictionary> newAvailableLinearVars = new Dictionary>(); - foreach (Absy absy in this.availableLinearVars.Keys) - { - HashSet vars = new HashSet(); - foreach (Variable var in this.availableLinearVars[absy]) - { - if (var is GlobalVariable) continue; - string domainName = FindDomainName(var); - if (this.linearDomains.ContainsKey(domainName)) - { - vars.Add(var); - } - } - newAvailableLinearVars[absy] = vars; - } - this.availableLinearVars = newAvailableLinearVars; - var temp = new Dictionary(); - foreach (Variable v in outParamToDomainName.Keys) - { - if (linearDomains.ContainsKey(outParamToDomainName[v])) - temp[v] = outParamToDomainName[v]; - } - this.outParamToDomainName = temp; - temp = new Dictionary(); - foreach (Variable v in varToDomainName.Keys) - { - if (linearDomains.ContainsKey(varToDomainName[v])) - temp[v] = varToDomainName[v]; - } - this.varToDomainName = temp; - temp = new Dictionary(); - foreach (Variable v in globalVarToDomainName.Keys) - { - if (linearDomains.ContainsKey(globalVarToDomainName[v])) - temp[v] = globalVarToDomainName[v]; - } - this.globalVarToDomainName = temp; - } - private void Error(Absy node, string message) - { - checkingContext.Error(node, message); - errorCount++; - } - public override Program VisitProgram(Program node) - { - foreach (GlobalVariable g in program.GlobalVariables) - { - string domainName = FindDomainName(g); - if (domainName != null) - { - globalVarToDomainName[g] = domainName; - } - } - return base.VisitProgram(node); - } - public override Function VisitFunction(Function node) - { - string domainName = QKeyValue.FindStringAttribute(node.Attributes, "linear"); - if (domainName != null) - { - if (!domainNameToCollectors.ContainsKey(domainName)) - { - domainNameToCollectors[domainName] = new Dictionary(); - } - if (node.InParams.Count == 1 && node.OutParams.Count == 1) - { - Type inType = node.InParams[0].TypedIdent.Type; - MapType outType = node.OutParams[0].TypedIdent.Type as MapType; - if (domainNameToCollectors[domainName].ContainsKey(inType)) - { - Error(node, string.Format("A collector for domain for input type has already been defined")); - } - else if (outType == null || outType.Arguments.Count != 1 || !outType.Result.Equals(Type.Bool)) - { - Error(node, "Output of a linear domain collector should be of set type"); - } - else - { - domainNameToCollectors[domainName][inType] = node; - } - } - else - { - Error(node, "Linear domain collector should have one input and one output parameter"); - } - } - return base.VisitFunction(node); - } - public override Implementation VisitImplementation(Implementation node) - { - node.PruneUnreachableBlocks(); - node.ComputePredecessorsForBlocks(); - GraphUtil.Graph graph = Program.GraphFromImpl(node); - graph.ComputeLoops(); - - HashSet start = new HashSet(globalVarToDomainName.Keys); - for (int i = 0; i < node.InParams.Count; i++) - { - Variable v = node.Proc.InParams[i]; - string domainName = FindDomainName(v); - if (domainName != null) - { - var kind = FindLinearKind(v); - inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind); - if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN) - { - start.Add(node.InParams[i]); - } - } - } - for (int i = 0; i < node.OutParams.Count; i++) - { - string domainName = FindDomainName(node.Proc.OutParams[i]); - if (domainName != null) - { - outParamToDomainName[node.OutParams[i]] = domainName; - } - } - - var oldErrorCount = this.errorCount; - var impl = base.VisitImplementation(node); - if (oldErrorCount < this.errorCount) - return impl; - - Stack dfsStack = new Stack(); - HashSet dfsStackAsSet = new HashSet(); - availableLinearVars[node.Blocks[0]] = start; - dfsStack.Push(node.Blocks[0]); - dfsStackAsSet.Add(node.Blocks[0]); - while (dfsStack.Count > 0) - { - Block b = dfsStack.Pop(); - dfsStackAsSet.Remove(b); - HashSet end = PropagateAvailableLinearVarsAcrossBlock(b); - if (b.TransferCmd is ReturnCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end)) - { - Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name)); - } - foreach (Variable v in node.InParams) - { - if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue; - Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name)); - } - foreach (Variable v in node.OutParams) - { - if (FindDomainName(v) == null || end.Contains(v)) continue; - Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name)); - } - continue; - } - GotoCmd gotoCmd = b.TransferCmd as GotoCmd; - foreach (Block target in gotoCmd.labelTargets) - { - if (!availableLinearVars.ContainsKey(target)) - { - availableLinearVars[target] = new HashSet(end); - dfsStack.Push(target); - dfsStackAsSet.Add(target); - } - else - { - var savedAvailableVars = new HashSet(availableLinearVars[target]); - availableLinearVars[target].IntersectWith(end); - if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target)) - { - dfsStack.Push(target); - dfsStackAsSet.Add(target); - } - } - } - } - - if (graph.Reducible) - { - foreach (Block header in graph.Headers) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header])) - { - Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name)); - } - } - } - return impl; - } - public void AddAvailableVars(CallCmd callCmd, HashSet start) - { - foreach (IdentifierExpr ie in callCmd.Outs) - { - if (FindDomainName(ie.Decl) == null) continue; - start.Add(ie.Decl); - } - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; - if (ie == null) continue; - Variable v = callCmd.Proc.InParams[i]; - if (FindDomainName(v) == null) continue; - if (FindLinearKind(v) == LinearKind.LINEAR_OUT) - { - start.Add(ie.Decl); - } - } - } - public void AddAvailableVars(ParCallCmd parCallCmd, HashSet start) - { - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - AddAvailableVars(callCmd, start); - } - } - private HashSet PropagateAvailableLinearVarsAcrossBlock(Block b) { - HashSet start = new HashSet(availableLinearVars[b]); - foreach (Cmd cmd in b.Cmds) - { - if (cmd is AssignCmd) - { - AssignCmd assignCmd = (AssignCmd)cmd; - for (int i = 0; i < assignCmd.Lhss.Count; i++) - { - if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue; - IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr; - if (!start.Contains(ie.Decl)) - { - Error(ie, "unavailable source for a linear read"); - } - else - { - start.Remove(ie.Decl); - } - } - foreach (AssignLhs assignLhs in assignCmd.Lhss) - { - if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue; - start.Add(assignLhs.DeepAssignedVariable); - } - } - else if (cmd is CallCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) - { - Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); - } - CallCmd callCmd = (CallCmd)cmd; - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - Variable param = callCmd.Proc.InParams[i]; - if (FindDomainName(param) == null) continue; - IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; - LinearKind paramKind = FindLinearKind(param); - if (start.Contains(ie.Decl)) - { - if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN) - { - start.Remove(ie.Decl); - } - } - else - { - if (paramKind == LinearKind.LINEAR_OUT) - { - start.Add(ie.Decl); - } - else - { - Error(ie, "unavailable source for a linear read"); - } - } - } - availableLinearVars[callCmd] = new HashSet(start); - AddAvailableVars(callCmd, start); - } - else if (cmd is ParCallCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) - { - Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); - } - ParCallCmd parCallCmd = (ParCallCmd)cmd; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - Variable param = callCmd.Proc.InParams[i]; - if (FindDomainName(param) == null) continue; - IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; - LinearKind paramKind = FindLinearKind(param); - if (start.Contains(ie.Decl)) - { - if (paramKind == LinearKind.LINEAR_IN) - { - start.Remove(ie.Decl); - } - } - else - { - if (paramKind == LinearKind.LINEAR_OUT) - { - start.Add(ie.Decl); - } - else - { - Error(ie, "unavailable source for a linear read"); - } - } - } - } - availableLinearVars[parCallCmd] = new HashSet(start); - AddAvailableVars(parCallCmd, start); - } - else if (cmd is HavocCmd) - { - HavocCmd havocCmd = (HavocCmd)cmd; - foreach (IdentifierExpr ie in havocCmd.Vars) - { - if (FindDomainName(ie.Decl) == null) continue; - start.Remove(ie.Decl); - } - } - else if (cmd is YieldCmd) - { - foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) - { - Error(cmd, string.Format("Global variable {0} must be available at a yield", g.Name)); - } - availableLinearVars[cmd] = new HashSet(start); - } - } - return start; - } - public string FindDomainName(Variable v) - { - if (globalVarToDomainName.ContainsKey(v)) - return globalVarToDomainName[v]; - if (inParamToLinearQualifier.ContainsKey(v)) - return inParamToLinearQualifier[v].domainName; - if (outParamToDomainName.ContainsKey(v)) - return outParamToDomainName[v]; - string domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear"); - if (domainName != null) - return domainName; - domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear_in"); - if (domainName != null) - return domainName; - return QKeyValue.FindStringAttribute(v.Attributes, "linear_out"); - } - public LinearKind FindLinearKind(Variable v) - { - if (globalVarToDomainName.ContainsKey(v)) - return LinearKind.LINEAR; - if (inParamToLinearQualifier.ContainsKey(v)) - return inParamToLinearQualifier[v].kind; - if (outParamToDomainName.ContainsKey(v)) - return LinearKind.LINEAR; - - if (QKeyValue.FindStringAttribute(v.Attributes, "linear") != null) - { - return LinearKind.LINEAR; - } - else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_in") != null) - { - return LinearKind.LINEAR_IN; - } - else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_out") != null) - { - return LinearKind.LINEAR_OUT; - } - else - { - Debug.Assert(false); - return LinearKind.LINEAR; - } - } - public override Variable VisitVariable(Variable node) - { - string domainName = FindDomainName(node); - if (domainName != null) - { - if (!domainNameToCollectors.ContainsKey(domainName)) - { - domainNameToCollectors[domainName] = new Dictionary(); - } - LinearKind kind = FindLinearKind(node); - if (kind != LinearKind.LINEAR) - { - if (node is GlobalVariable || node is LocalVariable || (node is Formal && !(node as Formal).InComing)) - { - Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)"); - } - } - } - return base.VisitVariable(node); - } - public override Cmd VisitAssignCmd(AssignCmd node) - { - HashSet rhsVars = new HashSet(); - for (int i = 0; i < node.Lhss.Count; i++) - { - AssignLhs lhs = node.Lhss[i]; - Variable lhsVar = lhs.DeepAssignedVariable; - string domainName = FindDomainName(lhsVar); - if (domainName == null) continue; - SimpleAssignLhs salhs = lhs as SimpleAssignLhs; - if (salhs == null) - { - Error(node, string.Format("Only simple assignment allowed on linear variable {0}", lhsVar.Name)); - continue; - } - IdentifierExpr rhs = node.Rhss[i] as IdentifierExpr; - if (rhs == null) - { - Error(node, string.Format("Only variable can be assigned to linear variable {0}", lhsVar.Name)); - continue; - } - string rhsDomainName = FindDomainName(rhs.Decl); - if (rhsDomainName == null) - { - Error(node, string.Format("Only linear variable can be assigned to linear variable {0}", lhsVar.Name)); - continue; - } - if (domainName != rhsDomainName) - { - Error(node, string.Format("Linear variable of domain {0} cannot be assigned to linear variable of domain {1}", rhsDomainName, domainName)); - continue; - } - if (rhsVars.Contains(rhs.Decl)) - { - Error(node, string.Format("Linear variable {0} can occur only once in the right-hand-side of an assignment", rhs.Decl.Name)); - continue; - } - rhsVars.Add(rhs.Decl); - } - return base.VisitAssignCmd(node); - } - public override Cmd VisitCallCmd(CallCmd node) - { - HashSet inVars = new HashSet(); - for (int i = 0; i < node.Proc.InParams.Count; i++) - { - Variable formal = node.Proc.InParams[i]; - string domainName = FindDomainName(formal); - if (domainName == null) continue; - IdentifierExpr actual = node.Ins[i] as IdentifierExpr; - if (actual == null) - { - Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name)); - continue; - } - string actualDomainName = FindDomainName(actual.Decl); - if (actualDomainName == null) - { - Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name)); - continue; - } - if (domainName != actualDomainName) - { - Error(node, "The domains of formal and actual parameters must be the same"); - continue; - } - if (actual.Decl is GlobalVariable) - { - Error(node, "Only local linear variable can be an actual input parameter of a procedure call"); - continue; - } - if (inVars.Contains(actual.Decl)) - { - Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name)); - continue; - } - inVars.Add(actual.Decl); - } - for (int i = 0; i < node.Proc.OutParams.Count; i++) - { - IdentifierExpr actual = node.Outs[i]; - string actualDomainName = FindDomainName(actual.Decl); - if (actualDomainName == null) continue; - Variable formal = node.Proc.OutParams[i]; - string domainName = FindDomainName(formal); - if (domainName == null) - { - Error(node, "Only a linear variable can be passed to a linear parameter"); - continue; - } - if (domainName != actualDomainName) - { - Error(node, "The domains of formal and actual parameters must be the same"); - continue; - } - if (actual.Decl is GlobalVariable) - { - Error(node, "Only local linear variable can be actual output parameter of a procedure call"); - continue; - } - } - return base.VisitCallCmd(node); - } - public override Cmd VisitParCallCmd(ParCallCmd node) - { - HashSet parallelCallInvars = new HashSet(); - foreach (CallCmd callCmd in node.CallCmds) - { - for (int i = 0; i < callCmd.Proc.InParams.Count; i++) - { - Variable formal = callCmd.Proc.InParams[i]; - string domainName = FindDomainName(formal); - if (domainName == null) continue; - IdentifierExpr actual = callCmd.Ins[i] as IdentifierExpr; - if (parallelCallInvars.Contains(actual.Decl)) - { - Error(node, string.Format("Linear variable {0} can occur only once as an input parameter of a parallel call", actual.Decl.Name)); - } - else - { - parallelCallInvars.Add(actual.Decl); - } - } - } - return base.VisitParCallCmd(node); - } - - public override Requires VisitRequires(Requires requires) - { - return requires; - } - - public override Ensures VisitEnsures(Ensures ensures) - { - return ensures; - } - - public IEnumerable AvailableLinearVars(Absy absy) - { - if (availableLinearVars.ContainsKey(absy)) - { - return availableLinearVars[absy]; - } - else - { - return new HashSet(); - } - } - - private void AddDisjointnessExpr(List newCmds, Absy absy, Dictionary domainNameToInputVar) - { - Dictionary> domainNameToScope = new Dictionary>(); - foreach (var domainName in linearDomains.Keys) - { - domainNameToScope[domainName] = new HashSet(); - } - foreach (Variable v in AvailableLinearVars(absy)) - { - var domainName = FindDomainName(v); - domainNameToScope[domainName].Add(v); - } - foreach (Variable v in program.GlobalVariables) - { - var domainName = FindDomainName(v); - if (domainName == null) continue; - domainNameToScope[domainName].Add(v); - } - foreach (string domainName in linearDomains.Keys) - { - newCmds.Add(new AssumeCmd(Token.NoToken, DisjointnessExpr(domainName, domainNameToInputVar[domainName], domainNameToScope[domainName]))); - } - } - - public void Transform() - { - foreach (var impl in program.Implementations) - { - Dictionary domainNameToInputVar = new Dictionary(); - foreach (string domainName in linearDomains.Keys) - { - var domain = linearDomains[domainName]; - Formal f = new Formal( - Token.NoToken, - new TypedIdent(Token.NoToken, - "linear_" + domainName + "_in", - new MapType(Token.NoToken, new List(), - new List { domain.elementType }, Type.Bool)), true); - impl.InParams.Add(f); - domainNameToInputVar[domainName] = f; - } - - foreach (Block b in impl.Blocks) - { - List newCmds = new List(); - for (int i = 0; i < b.Cmds.Count; i++) - { - Cmd cmd = b.Cmds[i]; - newCmds.Add(cmd); - if (cmd is CallCmd) - { - CallCmd callCmd = cmd as CallCmd; - if (callCmd.IsAsync) - { - foreach (var domainName in linearDomains.Keys) - { - var domain = linearDomains[domainName]; - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - callCmd.Ins.Add(expr); - } - } - else - { - Dictionary domainNameToExpr = new Dictionary(); - foreach (var domainName in linearDomains.Keys) - { - domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); - } - foreach (Variable v in AvailableLinearVars(callCmd)) - { - var domainName = FindDomainName(v); - var domain = linearDomains[domainName]; - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - domainNameToExpr[domainName] = expr; - } - foreach (var domainName in linearDomains.Keys) - { - callCmd.Ins.Add(domainNameToExpr[domainName]); - } - } - } - else if (cmd is ParCallCmd) - { - ParCallCmd parCallCmd = (ParCallCmd)cmd; - foreach (CallCmd callCmd in parCallCmd.CallCmds) - { - foreach (var domainName in linearDomains.Keys) - { - var domain = linearDomains[domainName]; - var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - callCmd.Ins.Add(expr); - } - } - } - else if (cmd is YieldCmd) - { - AddDisjointnessExpr(newCmds, cmd, domainNameToInputVar); - } - } - b.Cmds = newCmds; - } - - { - // Loops - impl.PruneUnreachableBlocks(); - impl.ComputePredecessorsForBlocks(); - GraphUtil.Graph g = Program.GraphFromImpl(impl); - g.ComputeLoops(); - if (g.Reducible) - { - foreach (Block header in g.Headers) - { - List newCmds = new List(); - AddDisjointnessExpr(newCmds, header, domainNameToInputVar); - newCmds.AddRange(header.Cmds); - header.Cmds = newCmds; - } - } - } - } - - foreach (var proc in program.Procedures) - { - Dictionary> domainNameToInputScope = new Dictionary>(); - Dictionary> domainNameToOutputScope = new Dictionary>(); - foreach (var domainName in linearDomains.Keys) - { - domainNameToInputScope[domainName] = new HashSet(); - domainNameToOutputScope[domainName] = new HashSet(); - - } - foreach (Variable v in globalVarToDomainName.Keys) - { - var domainName = globalVarToDomainName[v]; - domainNameToInputScope[domainName].Add(v); - domainNameToOutputScope[domainName].Add(v); - } - foreach (Variable v in proc.InParams) - { - var domainName = FindDomainName(v); - if (domainName == null) continue; - if (!this.linearDomains.ContainsKey(domainName)) continue; - domainNameToInputScope[domainName].Add(v); - } - foreach (Variable v in proc.OutParams) - { - var domainName = FindDomainName(v); - if (domainName == null) continue; - if (!this.linearDomains.ContainsKey(domainName)) continue; - domainNameToOutputScope[domainName].Add(v); - } - foreach (var domainName in linearDomains.Keys) - { - proc.Requires.Add(new Requires(true, DisjointnessExpr(domainName, domainNameToInputScope[domainName]))); - var domain = linearDomains[domainName]; - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); - proc.InParams.Add(f); - proc.Ensures.Add(new Ensures(true, DisjointnessExpr(domainName, f, domainNameToOutputScope[domainName]))); - } - } - - foreach (LinearDomain domain in linearDomains.Values) - { - program.AddTopLevelDeclaration(domain.mapConstBool); - program.AddTopLevelDeclaration(domain.mapConstInt); - program.AddTopLevelDeclaration(domain.mapEqInt); - program.AddTopLevelDeclaration(domain.mapImpBool); - program.AddTopLevelDeclaration(domain.mapOrBool); - foreach (Axiom axiom in domain.axioms) - { - program.AddTopLevelDeclaration(axiom); - } - } - - //int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; - //CommandLineOptions.Clo.PrintUnstructured = 1; - //PrintBplFile("lsd.bpl", program, false, false); - //CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; - } - - private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount) - { - Expr e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstInt), new List { new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(partitionCount)) }); - e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapEqInt), new List { Expr.Ident(partition), e }); - e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapImpBool), new List { ie, e }); - e = Expr.Eq(e, new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.True })); - return e; - } - - private Expr SubsetExprs(LinearDomain domain, HashSet scope, Variable partition, int count, Expr expr) - { - foreach (Variable v in scope) - { - if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; - Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); - expr = Expr.And(SubsetExpr(domain, ie, partition, count), expr); - count++; - } - expr = new ExistsExpr(Token.NoToken, new List { partition }, expr); - expr.Resolve(new ResolutionContext(null)); - expr.Typecheck(new TypecheckingContext(null)); - return expr; - } - - public Expr DisjointnessExpr(string domainName, Variable inputVar, HashSet scope) - { - LinearDomain domain = linearDomains[domainName]; - BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); - return SubsetExprs(domain, scope, partition, 1, SubsetExpr(domain, Expr.Ident(inputVar), partition, 0)); - } - - public Expr DisjointnessExpr(string domainName, HashSet scope) - { - LinearDomain domain = linearDomains[domainName]; - BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); - return SubsetExprs(domain, scope, partition, 0, Expr.True); - } - } - - public class LinearQualifier - { - public string domainName; - public LinearKind kind; - public LinearQualifier(string domainName, LinearKind kind) - { - this.domainName = domainName; - this.kind = kind; - } - } - - public class LinearDomain - { - public Function mapEqInt; - public Function mapConstInt; - public Function mapOrBool; - public Function mapImpBool; - public Function mapConstBool; - public List axioms; - public Type elementType; - public Dictionary collectors; - - public LinearDomain(Program program, string domainName, Dictionary collectors) - { - this.axioms = new List(); - this.collectors = collectors; - MapType setType = (MapType)collectors.First().Value.OutParams[0].TypedIdent.Type; - this.elementType = setType.Arguments[0]; - MapType mapTypeBool = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Bool); - MapType mapTypeInt = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Int); - this.mapOrBool = new Function(Token.NoToken, "linear_" + domainName + "_MapOr", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapOrBool.AddAttribute("builtin", "MapOr"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); - IdentifierExpr bie = Expr.Ident(b); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapOrBool), new List { aie, bie } ); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie } ); - var rhsTerm = Expr.Or(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie } ), - new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie} )); - var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, - new Trigger(Token.NoToken, true, new List { mapApplTerm }), - new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - this.mapImpBool = new Function(Token.NoToken, "linear_" + domainName + "_MapImp", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapImpBool.AddAttribute("builtin", "MapImp"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); - IdentifierExpr bie = Expr.Ident(b); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapImpBool), new List { aie, bie }); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); - var rhsTerm = Expr.Imp(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), - new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); - var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, - new Trigger(Token.NoToken, true, new List { mapApplTerm }), - new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - this.mapConstBool = new Function(Token.NoToken, "linear_" + domainName + "_MapConstBool", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Bool), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapConstBool.AddAttribute("builtin", "MapConst"); - } - else - { - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var trueTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), - new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.True }), xie }); - var trueAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, trueTerm); - trueAxiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, trueAxiomExpr)); - var falseTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), - new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.False }), xie }); - var falseAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, falseTerm)); - falseAxiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, falseAxiomExpr)); - } - - this.mapEqInt = new Function(Token.NoToken, "linear_" + domainName + "_MapEq", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt), true), - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapEqInt.AddAttribute("builtin", "MapEq"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt)); - IdentifierExpr bie = Expr.Ident(b); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapEqInt), new List { aie, bie }); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); - var rhsTerm = Expr.Eq(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), - new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); - var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, - new Trigger(Token.NoToken, true, new List { mapApplTerm }), - new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - this.mapConstInt = new Function(Token.NoToken, "linear_" + domainName + "_MapConstInt", - new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Int), true) }, - new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeInt), false)); - if (CommandLineOptions.Clo.UseArrayTheory) - { - this.mapConstInt.AddAttribute("builtin", "MapConst"); - } - else - { - BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", Type.Int)); - IdentifierExpr aie = Expr.Ident(a); - BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); - IdentifierExpr xie = Expr.Ident(x); - var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstInt), new List { aie }), xie }); - var axiomExpr = new ForallExpr(Token.NoToken, new List { a, x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, aie)); - axiomExpr.Typecheck(new TypecheckingContext(null)); - axioms.Add(new Axiom(Token.NoToken, axiomExpr)); - } - - foreach (var axiom in axioms) - { - axiom.Expr.Resolve(new ResolutionContext(null)); - axiom.Expr.Typecheck(new TypecheckingContext(null)); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Boogie; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public class LinearEraser : ReadOnlyVisitor + { + private QKeyValue RemoveLinearAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveLinearAttribute(iter.Next); + return (iter.Key == "linear" || iter.Key == "linear_in" || iter.Key == "linear_out") ? iter.Next : iter; + } + + public override Variable VisitVariable(Variable node) + { + node.Attributes = RemoveLinearAttribute(node.Attributes); + return base.VisitVariable(node); + } + + public override Function VisitFunction(Function node) + { + node.Attributes = RemoveLinearAttribute(node.Attributes); + return base.VisitFunction(node); + } + } + + public enum LinearKind { + LINEAR, + LINEAR_IN, + LINEAR_OUT + } + + public class LinearTypeChecker : ReadOnlyVisitor + { + public Program program; + public int errorCount; + public CheckingContext checkingContext; + public Dictionary> domainNameToCollectors; + private Dictionary> availableLinearVars; + public Dictionary inParamToLinearQualifier; + public Dictionary outParamToDomainName; + public Dictionary varToDomainName; + public Dictionary globalVarToDomainName; + public Dictionary linearDomains; + + public LinearTypeChecker(Program program) + { + this.program = program; + this.errorCount = 0; + this.checkingContext = new CheckingContext(null); + this.domainNameToCollectors = new Dictionary>(); + this.availableLinearVars = new Dictionary>(); + this.inParamToLinearQualifier = new Dictionary(); + this.outParamToDomainName = new Dictionary(); + this.varToDomainName = new Dictionary(); + this.globalVarToDomainName = new Dictionary(); + this.linearDomains = new Dictionary(); + } + public void TypeCheck() + { + this.VisitProgram(program); + foreach (string domainName in domainNameToCollectors.Keys) + { + var collectors = domainNameToCollectors[domainName]; + if (collectors.Count == 0) continue; + this.linearDomains[domainName] = new LinearDomain(program, domainName, collectors); + } + Dictionary> newAvailableLinearVars = new Dictionary>(); + foreach (Absy absy in this.availableLinearVars.Keys) + { + HashSet vars = new HashSet(); + foreach (Variable var in this.availableLinearVars[absy]) + { + if (var is GlobalVariable) continue; + string domainName = FindDomainName(var); + if (this.linearDomains.ContainsKey(domainName)) + { + vars.Add(var); + } + } + newAvailableLinearVars[absy] = vars; + } + this.availableLinearVars = newAvailableLinearVars; + var temp = new Dictionary(); + foreach (Variable v in outParamToDomainName.Keys) + { + if (linearDomains.ContainsKey(outParamToDomainName[v])) + temp[v] = outParamToDomainName[v]; + } + this.outParamToDomainName = temp; + temp = new Dictionary(); + foreach (Variable v in varToDomainName.Keys) + { + if (linearDomains.ContainsKey(varToDomainName[v])) + temp[v] = varToDomainName[v]; + } + this.varToDomainName = temp; + temp = new Dictionary(); + foreach (Variable v in globalVarToDomainName.Keys) + { + if (linearDomains.ContainsKey(globalVarToDomainName[v])) + temp[v] = globalVarToDomainName[v]; + } + this.globalVarToDomainName = temp; + } + private void Error(Absy node, string message) + { + checkingContext.Error(node, message); + errorCount++; + } + public override Program VisitProgram(Program node) + { + foreach (GlobalVariable g in program.GlobalVariables) + { + string domainName = FindDomainName(g); + if (domainName != null) + { + globalVarToDomainName[g] = domainName; + } + } + return base.VisitProgram(node); + } + public override Function VisitFunction(Function node) + { + string domainName = QKeyValue.FindStringAttribute(node.Attributes, "linear"); + if (domainName != null) + { + if (!domainNameToCollectors.ContainsKey(domainName)) + { + domainNameToCollectors[domainName] = new Dictionary(); + } + if (node.InParams.Count == 1 && node.OutParams.Count == 1) + { + Type inType = node.InParams[0].TypedIdent.Type; + MapType outType = node.OutParams[0].TypedIdent.Type as MapType; + if (domainNameToCollectors[domainName].ContainsKey(inType)) + { + Error(node, string.Format("A collector for domain for input type has already been defined")); + } + else if (outType == null || outType.Arguments.Count != 1 || !outType.Result.Equals(Type.Bool)) + { + Error(node, "Output of a linear domain collector should be of set type"); + } + else + { + domainNameToCollectors[domainName][inType] = node; + } + } + else + { + Error(node, "Linear domain collector should have one input and one output parameter"); + } + } + return base.VisitFunction(node); + } + public override Implementation VisitImplementation(Implementation node) + { + node.PruneUnreachableBlocks(); + node.ComputePredecessorsForBlocks(); + GraphUtil.Graph graph = Program.GraphFromImpl(node); + graph.ComputeLoops(); + + HashSet start = new HashSet(globalVarToDomainName.Keys); + for (int i = 0; i < node.InParams.Count; i++) + { + Variable v = node.Proc.InParams[i]; + string domainName = FindDomainName(v); + if (domainName != null) + { + var kind = FindLinearKind(v); + inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind); + if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN) + { + start.Add(node.InParams[i]); + } + } + } + for (int i = 0; i < node.OutParams.Count; i++) + { + string domainName = FindDomainName(node.Proc.OutParams[i]); + if (domainName != null) + { + outParamToDomainName[node.OutParams[i]] = domainName; + } + } + + var oldErrorCount = this.errorCount; + var impl = base.VisitImplementation(node); + if (oldErrorCount < this.errorCount) + return impl; + + Stack dfsStack = new Stack(); + HashSet dfsStackAsSet = new HashSet(); + availableLinearVars[node.Blocks[0]] = start; + dfsStack.Push(node.Blocks[0]); + dfsStackAsSet.Add(node.Blocks[0]); + while (dfsStack.Count > 0) + { + Block b = dfsStack.Pop(); + dfsStackAsSet.Remove(b); + HashSet end = PropagateAvailableLinearVarsAcrossBlock(b); + if (b.TransferCmd is ReturnCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end)) + { + Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name)); + } + foreach (Variable v in node.InParams) + { + if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue; + Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name)); + } + foreach (Variable v in node.OutParams) + { + if (FindDomainName(v) == null || end.Contains(v)) continue; + Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name)); + } + continue; + } + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + if (!availableLinearVars.ContainsKey(target)) + { + availableLinearVars[target] = new HashSet(end); + dfsStack.Push(target); + dfsStackAsSet.Add(target); + } + else + { + var savedAvailableVars = new HashSet(availableLinearVars[target]); + availableLinearVars[target].IntersectWith(end); + if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target)) + { + dfsStack.Push(target); + dfsStackAsSet.Add(target); + } + } + } + } + + if (graph.Reducible) + { + foreach (Block header in graph.Headers) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header])) + { + Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name)); + } + } + } + return impl; + } + public void AddAvailableVars(CallCmd callCmd, HashSet start) + { + foreach (IdentifierExpr ie in callCmd.Outs) + { + if (FindDomainName(ie.Decl) == null) continue; + start.Add(ie.Decl); + } + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + if (ie == null) continue; + Variable v = callCmd.Proc.InParams[i]; + if (FindDomainName(v) == null) continue; + if (FindLinearKind(v) == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + } + } + public void AddAvailableVars(ParCallCmd parCallCmd, HashSet start) + { + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + AddAvailableVars(callCmd, start); + } + } + private HashSet PropagateAvailableLinearVarsAcrossBlock(Block b) { + HashSet start = new HashSet(availableLinearVars[b]); + foreach (Cmd cmd in b.Cmds) + { + if (cmd is AssignCmd) + { + AssignCmd assignCmd = (AssignCmd)cmd; + for (int i = 0; i < assignCmd.Lhss.Count; i++) + { + if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue; + IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr; + if (!start.Contains(ie.Decl)) + { + Error(ie, "unavailable source for a linear read"); + } + else + { + start.Remove(ie.Decl); + } + } + foreach (AssignLhs assignLhs in assignCmd.Lhss) + { + if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue; + start.Add(assignLhs.DeepAssignedVariable); + } + } + else if (cmd is CallCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); + } + CallCmd callCmd = (CallCmd)cmd; + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable param = callCmd.Proc.InParams[i]; + if (FindDomainName(param) == null) continue; + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + LinearKind paramKind = FindLinearKind(param); + if (start.Contains(ie.Decl)) + { + if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN) + { + start.Remove(ie.Decl); + } + } + else + { + if (paramKind == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + else + { + Error(ie, "unavailable source for a linear read"); + } + } + } + availableLinearVars[callCmd] = new HashSet(start); + AddAvailableVars(callCmd, start); + } + else if (cmd is ParCallCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); + } + ParCallCmd parCallCmd = (ParCallCmd)cmd; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable param = callCmd.Proc.InParams[i]; + if (FindDomainName(param) == null) continue; + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + LinearKind paramKind = FindLinearKind(param); + if (start.Contains(ie.Decl)) + { + if (paramKind == LinearKind.LINEAR_IN) + { + start.Remove(ie.Decl); + } + } + else + { + if (paramKind == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + else + { + Error(ie, "unavailable source for a linear read"); + } + } + } + } + availableLinearVars[parCallCmd] = new HashSet(start); + AddAvailableVars(parCallCmd, start); + } + else if (cmd is HavocCmd) + { + HavocCmd havocCmd = (HavocCmd)cmd; + foreach (IdentifierExpr ie in havocCmd.Vars) + { + if (FindDomainName(ie.Decl) == null) continue; + start.Remove(ie.Decl); + } + } + else if (cmd is YieldCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a yield", g.Name)); + } + availableLinearVars[cmd] = new HashSet(start); + } + } + return start; + } + public string FindDomainName(Variable v) + { + if (globalVarToDomainName.ContainsKey(v)) + return globalVarToDomainName[v]; + if (inParamToLinearQualifier.ContainsKey(v)) + return inParamToLinearQualifier[v].domainName; + if (outParamToDomainName.ContainsKey(v)) + return outParamToDomainName[v]; + string domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear"); + if (domainName != null) + return domainName; + domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear_in"); + if (domainName != null) + return domainName; + return QKeyValue.FindStringAttribute(v.Attributes, "linear_out"); + } + public LinearKind FindLinearKind(Variable v) + { + if (globalVarToDomainName.ContainsKey(v)) + return LinearKind.LINEAR; + if (inParamToLinearQualifier.ContainsKey(v)) + return inParamToLinearQualifier[v].kind; + if (outParamToDomainName.ContainsKey(v)) + return LinearKind.LINEAR; + + if (QKeyValue.FindStringAttribute(v.Attributes, "linear") != null) + { + return LinearKind.LINEAR; + } + else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_in") != null) + { + return LinearKind.LINEAR_IN; + } + else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_out") != null) + { + return LinearKind.LINEAR_OUT; + } + else + { + Debug.Assert(false); + return LinearKind.LINEAR; + } + } + public override Variable VisitVariable(Variable node) + { + string domainName = FindDomainName(node); + if (domainName != null) + { + if (!domainNameToCollectors.ContainsKey(domainName)) + { + domainNameToCollectors[domainName] = new Dictionary(); + } + LinearKind kind = FindLinearKind(node); + if (kind != LinearKind.LINEAR) + { + if (node is GlobalVariable || node is LocalVariable || (node is Formal && !(node as Formal).InComing)) + { + Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)"); + } + } + } + return base.VisitVariable(node); + } + public override Cmd VisitAssignCmd(AssignCmd node) + { + HashSet rhsVars = new HashSet(); + for (int i = 0; i < node.Lhss.Count; i++) + { + AssignLhs lhs = node.Lhss[i]; + Variable lhsVar = lhs.DeepAssignedVariable; + string domainName = FindDomainName(lhsVar); + if (domainName == null) continue; + SimpleAssignLhs salhs = lhs as SimpleAssignLhs; + if (salhs == null) + { + Error(node, string.Format("Only simple assignment allowed on linear variable {0}", lhsVar.Name)); + continue; + } + IdentifierExpr rhs = node.Rhss[i] as IdentifierExpr; + if (rhs == null) + { + Error(node, string.Format("Only variable can be assigned to linear variable {0}", lhsVar.Name)); + continue; + } + string rhsDomainName = FindDomainName(rhs.Decl); + if (rhsDomainName == null) + { + Error(node, string.Format("Only linear variable can be assigned to linear variable {0}", lhsVar.Name)); + continue; + } + if (domainName != rhsDomainName) + { + Error(node, string.Format("Linear variable of domain {0} cannot be assigned to linear variable of domain {1}", rhsDomainName, domainName)); + continue; + } + if (rhsVars.Contains(rhs.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once in the right-hand-side of an assignment", rhs.Decl.Name)); + continue; + } + rhsVars.Add(rhs.Decl); + } + return base.VisitAssignCmd(node); + } + public override Cmd VisitCallCmd(CallCmd node) + { + HashSet inVars = new HashSet(); + for (int i = 0; i < node.Proc.InParams.Count; i++) + { + Variable formal = node.Proc.InParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) continue; + IdentifierExpr actual = node.Ins[i] as IdentifierExpr; + if (actual == null) + { + Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name)); + continue; + } + string actualDomainName = FindDomainName(actual.Decl); + if (actualDomainName == null) + { + Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name)); + continue; + } + if (domainName != actualDomainName) + { + Error(node, "The domains of formal and actual parameters must be the same"); + continue; + } + if (actual.Decl is GlobalVariable) + { + Error(node, "Only local linear variable can be an actual input parameter of a procedure call"); + continue; + } + if (inVars.Contains(actual.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name)); + continue; + } + inVars.Add(actual.Decl); + } + for (int i = 0; i < node.Proc.OutParams.Count; i++) + { + IdentifierExpr actual = node.Outs[i]; + string actualDomainName = FindDomainName(actual.Decl); + if (actualDomainName == null) continue; + Variable formal = node.Proc.OutParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) + { + Error(node, "Only a linear variable can be passed to a linear parameter"); + continue; + } + if (domainName != actualDomainName) + { + Error(node, "The domains of formal and actual parameters must be the same"); + continue; + } + if (actual.Decl is GlobalVariable) + { + Error(node, "Only local linear variable can be actual output parameter of a procedure call"); + continue; + } + } + return base.VisitCallCmd(node); + } + public override Cmd VisitParCallCmd(ParCallCmd node) + { + HashSet parallelCallInvars = new HashSet(); + foreach (CallCmd callCmd in node.CallCmds) + { + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable formal = callCmd.Proc.InParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) continue; + IdentifierExpr actual = callCmd.Ins[i] as IdentifierExpr; + if (parallelCallInvars.Contains(actual.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once as an input parameter of a parallel call", actual.Decl.Name)); + } + else + { + parallelCallInvars.Add(actual.Decl); + } + } + } + return base.VisitParCallCmd(node); + } + + public override Requires VisitRequires(Requires requires) + { + return requires; + } + + public override Ensures VisitEnsures(Ensures ensures) + { + return ensures; + } + + public IEnumerable AvailableLinearVars(Absy absy) + { + if (availableLinearVars.ContainsKey(absy)) + { + return availableLinearVars[absy]; + } + else + { + return new HashSet(); + } + } + + private void AddDisjointnessExpr(List newCmds, Absy absy, Dictionary domainNameToInputVar) + { + Dictionary> domainNameToScope = new Dictionary>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToScope[domainName] = new HashSet(); + } + foreach (Variable v in AvailableLinearVars(absy)) + { + var domainName = FindDomainName(v); + domainNameToScope[domainName].Add(v); + } + foreach (Variable v in program.GlobalVariables) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + domainNameToScope[domainName].Add(v); + } + foreach (string domainName in linearDomains.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, DisjointnessExpr(domainName, domainNameToInputVar[domainName], domainNameToScope[domainName]))); + } + } + + public void Transform() + { + foreach (var impl in program.Implementations) + { + Dictionary domainNameToInputVar = new Dictionary(); + foreach (string domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + Formal f = new Formal( + Token.NoToken, + new TypedIdent(Token.NoToken, + "linear_" + domainName + "_in", + new MapType(Token.NoToken, new List(), + new List { domain.elementType }, Type.Bool)), true); + impl.InParams.Add(f); + domainNameToInputVar[domainName] = f; + } + + foreach (Block b in impl.Blocks) + { + List newCmds = new List(); + for (int i = 0; i < b.Cmds.Count; i++) + { + Cmd cmd = b.Cmds[i]; + newCmds.Add(cmd); + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (callCmd.IsAsync) + { + foreach (var domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + callCmd.Ins.Add(expr); + } + } + else + { + Dictionary domainNameToExpr = new Dictionary(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); + } + foreach (Variable v in AvailableLinearVars(callCmd)) + { + var domainName = FindDomainName(v); + var domain = linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List { ie, domainNameToExpr[domainName] }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + foreach (var domainName in linearDomains.Keys) + { + callCmd.Ins.Add(domainNameToExpr[domainName]); + } + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = (ParCallCmd)cmd; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + foreach (var domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.False }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + callCmd.Ins.Add(expr); + } + } + } + else if (cmd is YieldCmd) + { + AddDisjointnessExpr(newCmds, cmd, domainNameToInputVar); + } + } + b.Cmds = newCmds; + } + + { + // Loops + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + GraphUtil.Graph g = Program.GraphFromImpl(impl); + g.ComputeLoops(); + if (g.Reducible) + { + foreach (Block header in g.Headers) + { + List newCmds = new List(); + AddDisjointnessExpr(newCmds, header, domainNameToInputVar); + newCmds.AddRange(header.Cmds); + header.Cmds = newCmds; + } + } + } + } + + foreach (var proc in program.Procedures) + { + Dictionary> domainNameToInputScope = new Dictionary>(); + Dictionary> domainNameToOutputScope = new Dictionary>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToInputScope[domainName] = new HashSet(); + domainNameToOutputScope[domainName] = new HashSet(); + + } + foreach (Variable v in globalVarToDomainName.Keys) + { + var domainName = globalVarToDomainName[v]; + domainNameToInputScope[domainName].Add(v); + domainNameToOutputScope[domainName].Add(v); + } + foreach (Variable v in proc.InParams) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + if (!this.linearDomains.ContainsKey(domainName)) continue; + domainNameToInputScope[domainName].Add(v); + } + foreach (Variable v in proc.OutParams) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + if (!this.linearDomains.ContainsKey(domainName)) continue; + domainNameToOutputScope[domainName].Add(v); + } + foreach (var domainName in linearDomains.Keys) + { + proc.Requires.Add(new Requires(true, DisjointnessExpr(domainName, domainNameToInputScope[domainName]))); + var domain = linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List(), new List { domain.elementType }, Type.Bool)), true); + proc.InParams.Add(f); + proc.Ensures.Add(new Ensures(true, DisjointnessExpr(domainName, f, domainNameToOutputScope[domainName]))); + } + } + + foreach (LinearDomain domain in linearDomains.Values) + { + program.AddTopLevelDeclaration(domain.mapConstBool); + program.AddTopLevelDeclaration(domain.mapConstInt); + program.AddTopLevelDeclaration(domain.mapEqInt); + program.AddTopLevelDeclaration(domain.mapImpBool); + program.AddTopLevelDeclaration(domain.mapOrBool); + foreach (Axiom axiom in domain.axioms) + { + program.AddTopLevelDeclaration(axiom); + } + } + + //int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; + //CommandLineOptions.Clo.PrintUnstructured = 1; + //PrintBplFile("lsd.bpl", program, false, false); + //CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; + } + + private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount) + { + Expr e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstInt), new List { new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(partitionCount)) }); + e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapEqInt), new List { Expr.Ident(partition), e }); + e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapImpBool), new List { ie, e }); + e = Expr.Eq(e, new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List { Expr.True })); + return e; + } + + private Expr SubsetExprs(LinearDomain domain, HashSet scope, Variable partition, int count, Expr expr) + { + foreach (Variable v in scope) + { + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List { Expr.Ident(v) }); + expr = Expr.And(SubsetExpr(domain, ie, partition, count), expr); + count++; + } + expr = new ExistsExpr(Token.NoToken, new List { partition }, expr); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + return expr; + } + + public Expr DisjointnessExpr(string domainName, Variable inputVar, HashSet scope) + { + LinearDomain domain = linearDomains[domainName]; + BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); + return SubsetExprs(domain, scope, partition, 1, SubsetExpr(domain, Expr.Ident(inputVar), partition, 0)); + } + + public Expr DisjointnessExpr(string domainName, HashSet scope) + { + LinearDomain domain = linearDomains[domainName]; + BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List(), new List { domain.elementType }, Microsoft.Boogie.Type.Int))); + return SubsetExprs(domain, scope, partition, 0, Expr.True); + } + } + + public class LinearQualifier + { + public string domainName; + public LinearKind kind; + public LinearQualifier(string domainName, LinearKind kind) + { + this.domainName = domainName; + this.kind = kind; + } + } + + public class LinearDomain + { + public Function mapEqInt; + public Function mapConstInt; + public Function mapOrBool; + public Function mapImpBool; + public Function mapConstBool; + public List axioms; + public Type elementType; + public Dictionary collectors; + + public LinearDomain(Program program, string domainName, Dictionary collectors) + { + this.axioms = new List(); + this.collectors = collectors; + MapType setType = (MapType)collectors.First().Value.OutParams[0].TypedIdent.Type; + this.elementType = setType.Arguments[0]; + MapType mapTypeBool = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Bool); + MapType mapTypeInt = new MapType(Token.NoToken, new List(), new List { this.elementType }, Type.Int); + this.mapOrBool = new Function(Token.NoToken, "linear_" + domainName + "_MapOr", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapOrBool.AddAttribute("builtin", "MapOr"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapOrBool), new List { aie, bie } ); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie } ); + var rhsTerm = Expr.Or(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie } ), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie} )); + var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, + new Trigger(Token.NoToken, true, new List { mapApplTerm }), + new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapImpBool = new Function(Token.NoToken, "linear_" + domainName + "_MapImp", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapImpBool.AddAttribute("builtin", "MapImp"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapImpBool), new List { aie, bie }); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); + var rhsTerm = Expr.Imp(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); + var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, + new Trigger(Token.NoToken, true, new List { mapApplTerm }), + new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapConstBool = new Function(Token.NoToken, "linear_" + domainName + "_MapConstBool", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Bool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapConstBool.AddAttribute("builtin", "MapConst"); + } + else + { + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var trueTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.True }), xie }); + var trueAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, trueTerm); + trueAxiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, trueAxiomExpr)); + var falseTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List { Expr.False }), xie }); + var falseAxiomExpr = new ForallExpr(Token.NoToken, new List { x }, Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, falseTerm)); + falseAxiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, falseAxiomExpr)); + } + + this.mapEqInt = new Function(Token.NoToken, "linear_" + domainName + "_MapEq", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapEqInt.AddAttribute("builtin", "MapEq"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapEqInt), new List { aie, bie }); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { mapApplTerm, xie }); + var rhsTerm = Expr.Eq(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { aie, xie }), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { bie, xie })); + var axiomExpr = new ForallExpr(Token.NoToken, new List(), new List { a, b }, null, + new Trigger(Token.NoToken, true, new List { mapApplTerm }), + new ForallExpr(Token.NoToken, new List { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapConstInt = new Function(Token.NoToken, "linear_" + domainName + "_MapConstInt", + new List { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Int), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeInt), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapConstInt.AddAttribute("builtin", "MapConst"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", Type.Int)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List { new NAryExpr(Token.NoToken, new FunctionCall(mapConstInt), new List { aie }), xie }); + var axiomExpr = new ForallExpr(Token.NoToken, new List { a, x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, aie)); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + foreach (var axiom in axioms) + { + axiom.Expr.Resolve(new ResolutionContext(null)); + axiom.Expr.Typecheck(new TypecheckingContext(null)); + } + } + } +} diff --git a/Source/Concurrency/Program.cs b/Source/Concurrency/Program.cs index 8042476e..b56e1cf3 100644 --- a/Source/Concurrency/Program.cs +++ b/Source/Concurrency/Program.cs @@ -1,44 +1,44 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Microsoft.Boogie -{ - public class Concurrency - { - public static void Transform(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker) - { - List originalDecls = new List(); - Program program = linearTypeChecker.program; - foreach (var decl in program.TopLevelDeclarations) - { - Procedure proc = decl as Procedure; - if (proc != null && moverTypeChecker.procToActionInfo.ContainsKey(proc)) - { - originalDecls.Add(proc); - continue; - } - Implementation impl = decl as Implementation; - if (impl != null && moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) - { - originalDecls.Add(impl); - } - } - - List decls = new List(); - if (!CommandLineOptions.Clo.TrustAtomicityTypes) - { - MoverCheck.AddCheckers(linearTypeChecker, moverTypeChecker, decls); - } - OwickiGries.AddCheckers(linearTypeChecker, moverTypeChecker, decls); - foreach (Declaration decl in decls) - { - decl.Attributes = OwickiGries.RemoveYieldsAttribute(decl.Attributes); - } - program.RemoveTopLevelDeclarations(x => originalDecls.Contains(x)); - program.AddTopLevelDeclarations(decls); - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.Boogie +{ + public class Concurrency + { + public static void Transform(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker) + { + List originalDecls = new List(); + Program program = linearTypeChecker.program; + foreach (var decl in program.TopLevelDeclarations) + { + Procedure proc = decl as Procedure; + if (proc != null && moverTypeChecker.procToActionInfo.ContainsKey(proc)) + { + originalDecls.Add(proc); + continue; + } + Implementation impl = decl as Implementation; + if (impl != null && moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) + { + originalDecls.Add(impl); + } + } + + List decls = new List(); + if (!CommandLineOptions.Clo.TrustAtomicityTypes) + { + MoverCheck.AddCheckers(linearTypeChecker, moverTypeChecker, decls); + } + OwickiGries.AddCheckers(linearTypeChecker, moverTypeChecker, decls); + foreach (Declaration decl in decls) + { + decl.Attributes = OwickiGries.RemoveYieldsAttribute(decl.Attributes); + } + program.RemoveTopLevelDeclarations(x => originalDecls.Contains(x)); + program.AddTopLevelDeclarations(decls); + } + + } +} diff --git a/Source/Concurrency/Properties/AssemblyInfo.cs b/Source/Concurrency/Properties/AssemblyInfo.cs index 48430488..7e90c12f 100644 --- a/Source/Concurrency/Properties/AssemblyInfo.cs +++ b/Source/Concurrency/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Concurrency")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Concurrency")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("867039c5-87dc-4f76-9f90-4f52afc90116")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Concurrency")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Concurrency")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("867039c5-87dc-4f76-9f90-4f52afc90116")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Concurrency/SimulationRelation.cs b/Source/Concurrency/SimulationRelation.cs index 7f130f76..c97ebfb7 100644 --- a/Source/Concurrency/SimulationRelation.cs +++ b/Source/Concurrency/SimulationRelation.cs @@ -1,197 +1,197 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie.GraphUtil; - -namespace Microsoft.Boogie -{ - public class SimulationRelation - { - class Graph - { - HashSet nodes; - Dictionary>> successors; - Dictionary>> predecessors; - - public Graph(List> edges) - { - nodes = new HashSet(); - successors = new Dictionary>>(); - predecessors = new Dictionary>>(); - foreach (Tuple edge in edges) - { - T source = edge.Item1; - L label = edge.Item2; - T dest = edge.Item3; - nodes.Add(source); - nodes.Add(dest); - if (!successors.ContainsKey(source)) - { - successors[source] = new Dictionary>(); - } - if (!successors[source].ContainsKey(label)) - { - successors[source][label] = new List(); - } - if (!predecessors.ContainsKey(dest)) - { - predecessors[dest] = new Dictionary>(); - } - if (!predecessors[dest].ContainsKey(label)) - { - predecessors[dest][label] = new List(); - } - successors[source][label].Add(dest); - predecessors[dest][label].Add(source); - } - } - - public IEnumerable Nodes { get { return nodes; } } - - public IEnumerable Post(T t, L l) - { - if (successors.ContainsKey(t) && successors[t].ContainsKey(l)) - { - return successors[t][l]; - } - else - { - return Enumerable.Empty(); - } - } - - public IEnumerable Post(IEnumerable set, L l) - { - return set.Select(x => Post(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); - } - - public IEnumerable Pre(T t, L l) - { - if (predecessors.ContainsKey(t) && predecessors[t].ContainsKey(l)) - { - return predecessors[t][l]; - } - else - { - return Enumerable.Empty(); - } - } - - public IEnumerable Pre(IEnumerable set, L l) - { - return set.Select(x => Pre(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); - } - - public IEnumerable PostLabels(T t) - { - if (successors.ContainsKey(t)) - { - return successors[t].Keys; - } - else - { - return Enumerable.Empty(); - } - } - - public IEnumerable PreLabels(T t) - { - if (predecessors.ContainsKey(t)) - { - return predecessors[t].Keys; - } - else - { - return Enumerable.Empty(); - } - } - } - - Graph aGraph; - Graph bGraph; - Dictionary> initialConstraints; - - public SimulationRelation(List> aEdges, List> bEdges, Dictionary> initialConstraints) - { - this.aGraph = new Graph(aEdges); - this.bGraph = new Graph(bEdges); - this.initialConstraints = initialConstraints; - } - - public Dictionary> ComputeSimulationRelation() - { - Dictionary> prevsim; - Dictionary> sim; - Dictionary, HashSet> remove; - Queue> workQueue; - - prevsim = new Dictionary>(); - sim = new Dictionary>(); - remove = new Dictionary, HashSet>(); - workQueue = new Queue>(); - foreach (var a in aGraph.Nodes) - { - prevsim[a] = new HashSet(bGraph.Nodes); - sim[a] = new HashSet(); - HashSet aOutgoingLabels = new HashSet(aGraph.PostLabels(a)); - foreach (var b in bGraph.Nodes) - { - IEnumerable bOutgoingLabels = bGraph.PostLabels(b); - if (aOutgoingLabels.IsSubsetOf(bOutgoingLabels)) - { - sim[a].Add(b); - } - } - if (initialConstraints.ContainsKey(a)) - { - sim[a].IntersectWith(initialConstraints[a]); - } - - foreach (var l in aGraph.PreLabels(a)) - { - Tuple x = new Tuple(a, l); - remove[x] = new HashSet(bGraph.Pre(prevsim[a], l).Except(bGraph.Pre(sim[a], l))); - if (remove[x].Count > 0) - { - workQueue.Enqueue(x); - } - } - } - - while (workQueue.Count > 0) - { - Tuple x = workQueue.Dequeue(); - A v = x.Item1; - foreach (A u in aGraph.Pre(v, x.Item2)) - { - foreach (B w in remove[x]) - { - if (sim[u].Contains(w)) - { - sim[u].Remove(w); - foreach (L l in bGraph.PreLabels(w)) - { - foreach (B b in bGraph.Pre(w, l)) - { - if (bGraph.Post(b, l).Intersect(sim[u]).Count() == 0) - { - Tuple z = new Tuple(u, l); - if (!remove.ContainsKey(z)) - remove[z] = new HashSet(); - remove[z].Add(b); - workQueue.Enqueue(z); - } - } - } - } - } - } - prevsim[v] = new HashSet(sim[v]); - remove[x] = new HashSet(); - } - - return sim; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + public class SimulationRelation + { + class Graph + { + HashSet nodes; + Dictionary>> successors; + Dictionary>> predecessors; + + public Graph(List> edges) + { + nodes = new HashSet(); + successors = new Dictionary>>(); + predecessors = new Dictionary>>(); + foreach (Tuple edge in edges) + { + T source = edge.Item1; + L label = edge.Item2; + T dest = edge.Item3; + nodes.Add(source); + nodes.Add(dest); + if (!successors.ContainsKey(source)) + { + successors[source] = new Dictionary>(); + } + if (!successors[source].ContainsKey(label)) + { + successors[source][label] = new List(); + } + if (!predecessors.ContainsKey(dest)) + { + predecessors[dest] = new Dictionary>(); + } + if (!predecessors[dest].ContainsKey(label)) + { + predecessors[dest][label] = new List(); + } + successors[source][label].Add(dest); + predecessors[dest][label].Add(source); + } + } + + public IEnumerable Nodes { get { return nodes; } } + + public IEnumerable Post(T t, L l) + { + if (successors.ContainsKey(t) && successors[t].ContainsKey(l)) + { + return successors[t][l]; + } + else + { + return Enumerable.Empty(); + } + } + + public IEnumerable Post(IEnumerable set, L l) + { + return set.Select(x => Post(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); + } + + public IEnumerable Pre(T t, L l) + { + if (predecessors.ContainsKey(t) && predecessors[t].ContainsKey(l)) + { + return predecessors[t][l]; + } + else + { + return Enumerable.Empty(); + } + } + + public IEnumerable Pre(IEnumerable set, L l) + { + return set.Select(x => Pre(x, l)).Aggregate(Enumerable.Empty(), (p, q) => p.Concat(q)); + } + + public IEnumerable PostLabels(T t) + { + if (successors.ContainsKey(t)) + { + return successors[t].Keys; + } + else + { + return Enumerable.Empty(); + } + } + + public IEnumerable PreLabels(T t) + { + if (predecessors.ContainsKey(t)) + { + return predecessors[t].Keys; + } + else + { + return Enumerable.Empty(); + } + } + } + + Graph aGraph; + Graph bGraph; + Dictionary> initialConstraints; + + public SimulationRelation(List> aEdges, List> bEdges, Dictionary> initialConstraints) + { + this.aGraph = new Graph(aEdges); + this.bGraph = new Graph(bEdges); + this.initialConstraints = initialConstraints; + } + + public Dictionary> ComputeSimulationRelation() + { + Dictionary> prevsim; + Dictionary> sim; + Dictionary, HashSet> remove; + Queue> workQueue; + + prevsim = new Dictionary>(); + sim = new Dictionary>(); + remove = new Dictionary, HashSet>(); + workQueue = new Queue>(); + foreach (var a in aGraph.Nodes) + { + prevsim[a] = new HashSet(bGraph.Nodes); + sim[a] = new HashSet(); + HashSet aOutgoingLabels = new HashSet(aGraph.PostLabels(a)); + foreach (var b in bGraph.Nodes) + { + IEnumerable bOutgoingLabels = bGraph.PostLabels(b); + if (aOutgoingLabels.IsSubsetOf(bOutgoingLabels)) + { + sim[a].Add(b); + } + } + if (initialConstraints.ContainsKey(a)) + { + sim[a].IntersectWith(initialConstraints[a]); + } + + foreach (var l in aGraph.PreLabels(a)) + { + Tuple x = new Tuple(a, l); + remove[x] = new HashSet(bGraph.Pre(prevsim[a], l).Except(bGraph.Pre(sim[a], l))); + if (remove[x].Count > 0) + { + workQueue.Enqueue(x); + } + } + } + + while (workQueue.Count > 0) + { + Tuple x = workQueue.Dequeue(); + A v = x.Item1; + foreach (A u in aGraph.Pre(v, x.Item2)) + { + foreach (B w in remove[x]) + { + if (sim[u].Contains(w)) + { + sim[u].Remove(w); + foreach (L l in bGraph.PreLabels(w)) + { + foreach (B b in bGraph.Pre(w, l)) + { + if (bGraph.Post(b, l).Intersect(sim[u]).Count() == 0) + { + Tuple z = new Tuple(u, l); + if (!remove.ContainsKey(z)) + remove[z] = new HashSet(); + remove[z].Add(b); + workQueue.Enqueue(z); + } + } + } + } + } + } + prevsim[v] = new HashSet(sim[v]); + remove[x] = new HashSet(); + } + + return sim; + } + } +} diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs index 0fedcd44..36c99b7b 100644 --- a/Source/Core/Absy.cs +++ b/Source/Core/Absy.cs @@ -1,4482 +1,4482 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- -namespace Microsoft.Boogie.AbstractInterpretation { - using System.Diagnostics; - using System.Diagnostics.Contracts; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - - public class CallSite { - public readonly Implementation/*!*/ Impl; - public readonly Block/*!*/ Block; - public readonly int Statement; // invariant: Block[Statement] is CallCmd - public readonly ProcedureSummaryEntry/*!*/ SummaryEntry; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Impl != null); - Contract.Invariant(Block != null); - Contract.Invariant(SummaryEntry != null); - } - - - public CallSite(Implementation impl, Block b, int stmt, ProcedureSummaryEntry summaryEntry) { - Contract.Requires(summaryEntry != null); - Contract.Requires(b != null); - Contract.Requires(impl != null); - this.Impl = impl; - this.Block = b; - this.Statement = stmt; - this.SummaryEntry = summaryEntry; - } - } - - public class ProcedureSummaryEntry { - - private HashSet/*!*/ _returnPoints; // whenever OnExit changes, we start analysis again at all the ReturnPoints - - public HashSet/*!*/ ReturnPoints { - get { - Contract.Ensures(Contract.Result>() != null); - return this._returnPoints; - } - set { - Contract.Requires(value != null); - this._returnPoints = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._returnPoints != null); - } - - public ProcedureSummaryEntry() { - this._returnPoints = new HashSet(); - } - - } // class - - public class ProcedureSummary : ArrayList/**/ - { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant( - !IsReadOnly && !IsFixedSize); - } - - public new ProcedureSummaryEntry/*!*/ this[int i] { - get { - Contract.Requires(0 <= i && i < Count); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull((ProcedureSummaryEntry/*!*/)base[i]); - } - } - - } // class -} // namespace - -namespace Microsoft.Boogie { - using System; - using System.Linq; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Diagnostics.Contracts; - using Microsoft.Boogie.AbstractInterpretation; - using Microsoft.Boogie.GraphUtil; - using Set = GSet; - - [ContractClass(typeof(AbsyContracts))] - public abstract class Absy { - private IToken/*!*/ _tok; - private int uniqueId; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._tok != null); - } - - public IToken tok { //Rename this property and "_tok" if possible - get { - Contract.Ensures(Contract.Result() != null); - return this._tok; - } - set { - Contract.Requires(value != null); - this._tok = value; - } - } - - public int Line { - get { - return tok != null ? tok.line : -1; - } - } - public int Col { - get { - return tok != null ? tok.col : -1; - } - } - - public Absy(IToken tok) { - Contract.Requires(tok != null); - this._tok = tok; - this.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); - } - - private static int CurrentAbsyNodeId = -1; - - // We uniquely number every AST node to make them - // suitable for our implementation of functional maps. - // - public int UniqueId { - get { - return this.uniqueId; - } - } - - private const int indent_size = 2; - protected static string Indent(int level) { - return new string(' ', (indent_size * level)); - } - [NeedsContracts] - public abstract void Resolve(ResolutionContext/*!*/ rc); - - /// - /// Requires the object to have been successfully resolved. - /// - /// - [NeedsContracts] - public abstract void Typecheck(TypecheckingContext/*!*/ tc); - /// - /// Intorduced this so the uniqueId is not the same on a cloned object. - /// - /// - public virtual Absy Clone() { - Contract.Ensures(Contract.Result() != null); - Absy/*!*/ result = cce.NonNull((Absy/*!*/)this.MemberwiseClone()); - result.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); // BUGBUG?? - - if (InternalNumberedMetadata != null) { - // This should probably use the lock - result.InternalNumberedMetadata = new List(this.InternalNumberedMetadata); - } - - return result; - } - - public virtual Absy StdDispatch(StandardVisitor visitor) { - Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - System.Diagnostics.Debug.Fail("Unknown Absy node type: " + this.GetType()); - throw new System.NotImplementedException(); - } - - #region numberedmetadata - // Implementation of Numbered Metadata - // This allows any number of arbitrary objects to be - // associated with an instance of an Absy at run time - // in a type safe manner using an integer as a key. - - // We could use a dictionary but we use a List for look up speed - // For this to work well the user needs to use small integers as - // keys. The list is created lazily to minimise memory overhead. - private volatile List InternalNumberedMetadata = null; - - // The lock exists to ensure that InternalNumberedMetadata is a singleton - // for every instance of this class. - // It is static to minimise the memory overhead (we don't want a lock per instance). - private static readonly Object NumberedMetadataLock = new object(); - - /// - /// Gets the number of meta data objects associated with this instance - /// - /// The numbered meta data count. - public int NumberedMetaDataCount - { - get { return InternalNumberedMetadata == null? 0: InternalNumberedMetadata.Count; } - } - - /// - /// Gets an IEnumerable over the numbered metadata associated - /// with this instance. - /// - /// - /// The numbered meta data enumerable that looks like the Enumerable - /// of a dictionary. - /// - public IEnumerable> NumberedMetadata - { - get { - if (InternalNumberedMetadata == null) - return Enumerable.Empty>(); - else - return InternalNumberedMetadata.Select((v, index) => new KeyValuePair(index, v)); - } - } - - /// - /// Gets the metatdata at specified index. - /// ArgumentOutOfRange exception is raised if it is not available. - /// InvalidCastExcpetion is raised if the metadata is available but the wrong type was requested. - /// - /// The stored metadata of type T - /// The index of the metadata - /// The type of the metadata object required - public T GetMetadata(int index) { - // We aren't using NumberedMetadataLock for speed. Perhaps we should be using it? - if (InternalNumberedMetadata == null) - throw new ArgumentOutOfRangeException(); - - if (InternalNumberedMetadata[index] is T) - return (T) InternalNumberedMetadata[index]; - else if (InternalNumberedMetadata[index] == null) { - throw new InvalidCastException("Numbered metadata " + index + - " is null which cannot be casted to " + typeof(T)); - } - else { - throw new InvalidCastException("Numbered metadata " + index + - " is of type " + InternalNumberedMetadata[index].GetType() + - " rather than requested type " + typeof(T)); - } - } - - private void InitialiseNumberedMetadata() { - // Ensure InternalNumberedMetadata is a singleton - if (InternalNumberedMetadata == null) { - lock (NumberedMetadataLock) { - if (InternalNumberedMetadata == null) - InternalNumberedMetadata = new List(); - } - } - } - - /// - /// Sets the metadata for this instace at a specified index. - /// - /// The index of the metadata - /// The value to set - /// The type of value - public void SetMetadata(int index, T value) { - InitialiseNumberedMetadata(); - - if (index < 0) - throw new IndexOutOfRangeException(); - - lock (NumberedMetadataLock) { - if (index < InternalNumberedMetadata.Count) - InternalNumberedMetadata[index] = value; - else { - // Make sure expansion only happens once whilst we pad - if (InternalNumberedMetadata.Capacity <= index) { - // Use the next available power of 2 - InternalNumberedMetadata.Capacity = (int) Math.Pow(2, Math.Ceiling(Math.Log(index+1,2))); - } - - // Pad with nulls - while (InternalNumberedMetadata.Count < index) - InternalNumberedMetadata.Add (null); - - InternalNumberedMetadata.Add(value); - Debug.Assert(InternalNumberedMetadata.Count == (index + 1)); - } - } - } - - #endregion - - } - - [ContractClassFor(typeof(Absy))] - public abstract class AbsyContracts : Absy { - public override void Resolve(ResolutionContext rc) { - Contract.Requires(rc != null); - throw new NotImplementedException(); - } - public AbsyContracts() :base(null){ - - } - public override void Typecheck(TypecheckingContext tc) { - Contract.Requires(tc != null); - throw new NotImplementedException(); - } - } - - public interface IPotentialErrorNode - { - TGet ErrorData - { - get; - } - } - - public interface IPotentialErrorNode : IPotentialErrorNode - { - new TSet ErrorData - { - set; - } - } - - public class Program : Absy { - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(this.topLevelDeclarations)); - Contract.Invariant(cce.NonNullElements(this.globalVariablesCache, true)); - } - - public Program() - : base(Token.NoToken) { - this.topLevelDeclarations = new List(); - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.SetToken(this); - this.topLevelDeclarations.Emit(stream); - } - - public void ProcessDatatypeConstructors() { - Dictionary constructors = new Dictionary(); - List prunedTopLevelDeclarations = new List(); - foreach (Declaration decl in TopLevelDeclarations) { - Function func = decl as Function; - if (func == null || !QKeyValue.FindBoolAttribute(decl.Attributes, "constructor")) { - prunedTopLevelDeclarations.Add(decl); - continue; - } - if (constructors.ContainsKey(func.Name)) continue; - DatatypeConstructor constructor = new DatatypeConstructor(func); - constructors.Add(func.Name, constructor); - prunedTopLevelDeclarations.Add(constructor); - } - ClearTopLevelDeclarations(); - AddTopLevelDeclarations(prunedTopLevelDeclarations); - - foreach (DatatypeConstructor f in constructors.Values) { - for (int i = 0; i < f.InParams.Count; i++) { - DatatypeSelector selector = new DatatypeSelector(f, i); - f.selectors.Add(selector); - AddTopLevelDeclaration(selector); - } - DatatypeMembership membership = new DatatypeMembership(f); - f.membership = membership; - AddTopLevelDeclaration(membership); - } - } - - /// - /// Returns the number of name resolution errors. - /// - /// - public int Resolve() { - return Resolve((IErrorSink)null); - } - - public int Resolve(IErrorSink errorSink) { - ResolutionContext rc = new ResolutionContext(errorSink); - Resolve(rc); - return rc.ErrorCount; - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Helpers.ExtraTraceInformation("Starting resolution"); - - foreach (var d in TopLevelDeclarations) { - d.Register(rc); - } - - ResolveTypes(rc); - - var prunedTopLevelDecls = new List(); - foreach (var d in TopLevelDeclarations) { - if (QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) { - continue; - } - // resolve all the non-type-declarations - if (!(d is TypeCtorDecl || d is TypeSynonymDecl)) { - int e = rc.ErrorCount; - d.Resolve(rc); - 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); - } - ClearTopLevelDeclarations(); - AddTopLevelDeclarations(prunedTopLevelDecls); - - foreach (var v in Variables) { - v.ResolveWhere(rc); - } - } - - private void ResolveTypes(ResolutionContext rc) { - Contract.Requires(rc != null); - // first resolve type constructors - foreach (var d in TopLevelDeclarations.OfType()) { - if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) - d.Resolve(rc); - } - - // collect type synonym declarations - List/*!*/ synonymDecls = new List(); - foreach (var d in TopLevelDeclarations.OfType()) { - Contract.Assert(d != null); - if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) - synonymDecls.Add((TypeSynonymDecl)d); - } - - // then resolve the type synonyms by a simple - // fixed-point iteration - TypeSynonymDecl.ResolveTypeSynonyms(synonymDecls, rc); - } - - public int Typecheck() { - return this.Typecheck((IErrorSink)null); - } - - public int Typecheck(IErrorSink errorSink) { - TypecheckingContext tc = new TypecheckingContext(errorSink); - Typecheck(tc); - return tc.ErrorCount; - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Helpers.ExtraTraceInformation("Starting typechecking"); - - int oldErrorCount = tc.ErrorCount; - foreach (var d in TopLevelDeclarations) { - d.Typecheck(tc); - } - - if (oldErrorCount == tc.ErrorCount) { - // check whether any type proxies have remained uninstantiated - TypeAmbiguitySeeker/*!*/ seeker = new TypeAmbiguitySeeker(tc); - foreach (var d in TopLevelDeclarations) { - seeker.Visit(d); - } - } - } - - public override Absy Clone() - { - var cloned = (Program)base.Clone(); - cloned.topLevelDeclarations = new List(); - cloned.AddTopLevelDeclarations(topLevelDeclarations); - return cloned; - } - - [Rep] - private List/*!*/ topLevelDeclarations; - - public IEnumerable TopLevelDeclarations - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return topLevelDeclarations.AsReadOnly(); - } - - set - { - Contract.Requires(value != null); - // materialize the decls, in case there is any dependency - // back on topLevelDeclarations - var v = value.ToList(); - // remove null elements - v.RemoveAll(d => (d == null)); - // now clear the decls - ClearTopLevelDeclarations(); - // and add the values - AddTopLevelDeclarations(v); - } - } - - public void AddTopLevelDeclaration(Declaration decl) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - Contract.Requires(decl != null); - - topLevelDeclarations.Add(decl); - this.globalVariablesCache = null; - } - - public void AddTopLevelDeclarations(IEnumerable decls) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - Contract.Requires(cce.NonNullElements(decls)); - - topLevelDeclarations.AddRange(decls); - this.globalVariablesCache = null; - } - - public void RemoveTopLevelDeclaration(Declaration decl) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - - topLevelDeclarations.Remove(decl); - this.globalVariablesCache = null; - } - - public void RemoveTopLevelDeclarations(Predicate match) - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - - topLevelDeclarations.RemoveAll(match); - this.globalVariablesCache = null; - } - - public void ClearTopLevelDeclarations() - { - Contract.Requires(!TopLevelDeclarationsAreFrozen); - - topLevelDeclarations.Clear(); - this.globalVariablesCache = null; - } - - bool topLevelDeclarationsAreFrozen; - public bool TopLevelDeclarationsAreFrozen { get { return topLevelDeclarationsAreFrozen; } } - public void FreezeTopLevelDeclarations() - { - topLevelDeclarationsAreFrozen = true; - } - - Dictionary implementationsCache; - public IEnumerable Implementations - { - get - { - if (implementationsCache != null) - { - return implementationsCache.Values; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - implementationsCache = result.ToDictionary(p => p.Id); - } - return result; - } - } - - public Implementation FindImplementation(string id) - { - Implementation result = null; - if (implementationsCache != null && implementationsCache.TryGetValue(id, out result)) - { - return result; - } - else - { - return Implementations.FirstOrDefault(i => i.Id == id); - } - } - - List axiomsCache; - public IEnumerable Axioms - { - get - { - if (axiomsCache != null) - { - return axiomsCache; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - axiomsCache = result.ToList(); - } - return result; - } - } - - Dictionary proceduresCache; - public IEnumerable Procedures - { - get - { - if (proceduresCache != null) - { - return proceduresCache.Values; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - proceduresCache = result.ToDictionary(p => p.Name); - } - return result; - } - } - - public Procedure FindProcedure(string name) - { - Procedure result = null; - if (proceduresCache != null && proceduresCache.TryGetValue(name, out result)) - { - return result; - } - else - { - return Procedures.FirstOrDefault(p => p.Name == name); - } - } - - Dictionary functionsCache; - public IEnumerable Functions - { - get - { - if (functionsCache != null) - { - return functionsCache.Values; - } - var result = TopLevelDeclarations.OfType(); - if (topLevelDeclarationsAreFrozen) - { - functionsCache = result.ToDictionary(f => f.Name); - } - return result; - } - } - - public Function FindFunction(string name) - { - Function result = null; - if (functionsCache != null && functionsCache.TryGetValue(name, out result)) - { - return result; - } - else - { - return Functions.FirstOrDefault(f => f.Name == name); - } - } - - public IEnumerable Variables - { - get - { - return TopLevelDeclarations.OfType(); - } - } - - public IEnumerable Constants - { - get - { - return TopLevelDeclarations.OfType(); - } - } - - private IEnumerable globalVariablesCache = null; - public List/*!*/ GlobalVariables - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - if (globalVariablesCache == null) - globalVariablesCache = TopLevelDeclarations.OfType(); - - return new List(globalVariablesCache); - } - } - - public IEnumerable Blocks() - { - return Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item); - } - - public void ComputeStronglyConnectedComponents() { - foreach (var d in this.TopLevelDeclarations) { - d.ComputeStronglyConnectedComponents(); - } - } - - /// - /// Reset the abstract stated computed before - /// - public void ResetAbstractInterpretationState() { - foreach (var d in this.TopLevelDeclarations) { - d.ResetAbstractInterpretationState(); - } - } - - public void UnrollLoops(int n, bool uc) { - Contract.Requires(0 <= n); - foreach (var impl in Implementations) { - if (impl.Blocks != null && impl.Blocks.Count > 0) { - cce.BeginExpose(impl); - { - Block start = impl.Blocks[0]; - Contract.Assume(start != null); - Contract.Assume(cce.IsConsistent(start)); - impl.Blocks = LoopUnroll.UnrollLoops(start, n, uc); - impl.FreshenCaptureStates(); - } - cce.EndExpose(); - } - } - } - - void CreateProceduresForLoops(Implementation impl, Graph/*!*/ g, - List/*!*/ loopImpls, - Dictionary> fullMap) { - Contract.Requires(impl != null); - Contract.Requires(cce.NonNullElements(loopImpls)); - // Enumerate the headers - // for each header h: - // create implementation p_h with - // inputs = inputs, outputs, and locals of impl - // outputs = outputs and locals of impl - // locals = empty set - // add call o := p_h(i) at the beginning of the header block - // break the back edges whose target is h - // Enumerate the headers again to create the bodies of p_h - // for each header h: - // compute the loop corresponding to h - // make copies of all blocks in the loop for h - // delete all target edges that do not go to a block in the loop - // create a new entry block and a new return block - // add edges from entry block to the loop header and the return block - // add calls o := p_h(i) at the end of the blocks that are sources of back edges - foreach (Block block in impl.Blocks) - { - AddToFullMap(fullMap, impl.Name, block.Label, block); - } - - bool detLoopExtract = CommandLineOptions.Clo.DeterministicExtractLoops; - - Dictionary/*!*/>/*!*/ loopHeaderToInputs = new Dictionary/*!*/>(); - Dictionary/*!*/>/*!*/ loopHeaderToOutputs = new Dictionary/*!*/>(); - Dictionary/*!*/>/*!*/ loopHeaderToSubstMap = new Dictionary/*!*/>(); - Dictionary/*!*/ loopHeaderToLoopProc = new Dictionary(); - Dictionary/*!*/ loopHeaderToCallCmd1 = new Dictionary(); - Dictionary loopHeaderToCallCmd2 = new Dictionary(); - Dictionary loopHeaderToAssignCmd = new Dictionary(); - - foreach (Block/*!*/ header in g.Headers) { - Contract.Assert(header != null); - Contract.Assert(header != null); - List inputs = new List(); - List outputs = new List(); - List callInputs1 = new List(); - List callOutputs1 = new List(); - List callInputs2 = new List(); - List callOutputs2 = new List(); - List lhss = new List(); - List rhss = new List(); - Dictionary substMap = new Dictionary(); // Variable -> IdentifierExpr - - List/*!*/ targets = new List(); - HashSet footprint = new HashSet(); - - foreach (Block/*!*/ b in g.BackEdgeNodes(header)) - { - Contract.Assert(b != null); - foreach (Block/*!*/ block in g.NaturalLoops(header, b)) - { - Contract.Assert(block != null); - foreach (Cmd/*!*/ cmd in block.Cmds) - { - Contract.Assert(cmd != null); - cmd.AddAssignedVariables(targets); - - VariableCollector c = new VariableCollector(); - c.Visit(cmd); - footprint.UnionWith(c.usedVars); - } - } - } - - List/*!*/ globalMods = new List(); - Set targetSet = new Set(); - foreach (Variable/*!*/ v in targets) - { - Contract.Assert(v != null); - if (targetSet.Contains(v)) - continue; - targetSet.Add(v); - if (v is GlobalVariable) - globalMods.Add(new IdentifierExpr(Token.NoToken, v)); - } - - foreach (Variable v in impl.InParams) { - Contract.Assert(v != null); - if (!footprint.Contains(v)) continue; - callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); - inputs.Add(f); - callInputs2.Add(new IdentifierExpr(Token.NoToken, f)); - substMap[v] = new IdentifierExpr(Token.NoToken, f); - } - foreach (Variable v in impl.OutParams) { - Contract.Assert(v != null); - if (!footprint.Contains(v)) continue; - callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); - inputs.Add(f1); - if (targetSet.Contains(v)) - { - callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); - outputs.Add(f2); - callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); - rhss.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f2); - } - else - { - callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f1); - } - } - foreach (Variable v in impl.LocVars) { - Contract.Assert(v != null); - if (!footprint.Contains(v)) continue; - callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); - inputs.Add(f1); - if (targetSet.Contains(v)) - { - callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); - Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); - outputs.Add(f2); - callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); - lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); - rhss.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f2); - } - else - { - callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); - substMap[v] = new IdentifierExpr(Token.NoToken, f1); - } - } - - loopHeaderToInputs[header] = inputs; - loopHeaderToOutputs[header] = outputs; - loopHeaderToSubstMap[header] = substMap; - LoopProcedure loopProc = new LoopProcedure(impl, header, inputs, outputs, globalMods); - loopHeaderToLoopProc[header] = loopProc; - - CallCmd callCmd1 = new CallCmd(Token.NoToken, loopProc.Name, callInputs1, callOutputs1); - callCmd1.Proc = loopProc; - loopHeaderToCallCmd1[header] = callCmd1; - - CallCmd callCmd2 = new CallCmd(Token.NoToken, loopProc.Name, callInputs2, callOutputs2); - callCmd2.Proc = loopProc; - loopHeaderToCallCmd2[header] = callCmd2; - - Debug.Assert(lhss.Count == rhss.Count); - if (lhss.Count > 0) - { - AssignCmd assignCmd = new AssignCmd(Token.NoToken, lhss, rhss); - loopHeaderToAssignCmd[header] = assignCmd; - } - } - - // Keep track of the new blocks created: maps a header node to the - // header_last block that was created because of splitting header. - Dictionary newBlocksCreated = new Dictionary(); - - bool headRecursion = false; // testing an option to put recursive call before loop body - - IEnumerable sortedHeaders = g.SortHeadersByDominance(); - foreach (Block/*!*/ header in sortedHeaders) - { - Contract.Assert(header != null); - LoopProcedure loopProc = loopHeaderToLoopProc[header]; - Dictionary blockMap = new Dictionary(); - HashSet dummyBlocks = new HashSet(); - - CodeCopier codeCopier = new CodeCopier(loopHeaderToSubstMap[header]); // fix me - List inputs = loopHeaderToInputs[header]; - List outputs = loopHeaderToOutputs[header]; - int si_unique_loc = 1; // Added by AL: to distinguish the back edges - foreach (Block/*!*/ source in g.BackEdgeNodes(header)) { - Contract.Assert(source != null); - foreach (Block/*!*/ block in g.NaturalLoops(header, source)) { - Contract.Assert(block != null); - if (blockMap.ContainsKey(block)) - continue; - Block newBlock = new Block(); - newBlock.Label = block.Label; - if (headRecursion && block == header) - { - CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); - addUniqueCallAttr(si_unique_loc, callCmd); - si_unique_loc++; - newBlock.Cmds.Add(callCmd); // add the recursive call at head of loop - var rest = codeCopier.CopyCmdSeq(block.Cmds); - newBlock.Cmds.AddRange(rest); - } - else - newBlock.Cmds = codeCopier.CopyCmdSeq(block.Cmds); - blockMap[block] = newBlock; - if (newBlocksCreated.ContainsKey(block)) - { - Block newBlock2 = new Block(); - newBlock2.Label = newBlocksCreated[block].Label; - newBlock2.Cmds = codeCopier.CopyCmdSeq(newBlocksCreated[block].Cmds); - blockMap[newBlocksCreated[block]] = newBlock2; - } - //for detLoopExtract, need the immediate successors even outside the loop - if (detLoopExtract) { - GotoCmd auxGotoCmd = block.TransferCmd as GotoCmd; - Contract.Assert(auxGotoCmd != null && auxGotoCmd.labelNames != null && - auxGotoCmd.labelTargets != null && auxGotoCmd.labelTargets.Count >= 1); - foreach(var bl in auxGotoCmd.labelTargets) { - bool found = false; - foreach(var n in g.NaturalLoops(header, source)) { //very expensive, can we do a contains? - if (bl == n) { //clarify: is this the right comparison? - found = true; - break; - } - } - if (!found) { - Block auxNewBlock = new Block(); - auxNewBlock.Label = ((Block)bl).Label; - auxNewBlock.Cmds = codeCopier.CopyCmdSeq(((Block)bl).Cmds); - //add restoration code for such blocks - if (loopHeaderToAssignCmd.ContainsKey(header)) - { - AssignCmd assignCmd = loopHeaderToAssignCmd[header]; - auxNewBlock.Cmds.Add(assignCmd); - } - List lhsg = new List(); - List/*!*/ globalsMods = loopHeaderToLoopProc[header].Modifies; - foreach (IdentifierExpr gl in globalsMods) - lhsg.Add(new SimpleAssignLhs(Token.NoToken, gl)); - List rhsg = new List(); - foreach (IdentifierExpr gl in globalsMods) - rhsg.Add(new OldExpr(Token.NoToken, gl)); - if (lhsg.Count != 0) - { - AssignCmd globalAssignCmd = new AssignCmd(Token.NoToken, lhsg, rhsg); - auxNewBlock.Cmds.Add(globalAssignCmd); - } - blockMap[(Block)bl] = auxNewBlock; - } - } - - } - } - - List cmdSeq; - if (headRecursion) - cmdSeq = new List(); - else - { - CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); - addUniqueCallAttr(si_unique_loc, callCmd); - si_unique_loc++; - cmdSeq = new List { callCmd }; - } - - Block/*!*/ block1 = new Block(Token.NoToken, source.Label + "_dummy", - new List{ new AssumeCmd(Token.NoToken, Expr.False) }, new ReturnCmd(Token.NoToken)); - Block/*!*/ block2 = new Block(Token.NoToken, block1.Label, - cmdSeq, new ReturnCmd(Token.NoToken)); - impl.Blocks.Add(block1); - dummyBlocks.Add(block1.Label); - - GotoCmd gotoCmd = source.TransferCmd as GotoCmd; - Contract.Assert(gotoCmd != null && gotoCmd.labelNames != null && gotoCmd.labelTargets != null && gotoCmd.labelTargets.Count >= 1); - List/*!*/ newLabels = new List(); - List/*!*/ newTargets = new List(); - for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { - if (gotoCmd.labelTargets[i] == header) - continue; - newTargets.Add(gotoCmd.labelTargets[i]); - newLabels.Add(gotoCmd.labelNames[i]); - } - newTargets.Add(block1); - newLabels.Add(block1.Label); - gotoCmd.labelNames = newLabels; - gotoCmd.labelTargets = newTargets; - blockMap[block1] = block2; - } - List/*!*/ blocks = new List(); - Block exit = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); - GotoCmd cmd = new GotoCmd(Token.NoToken, - new List { cce.NonNull(blockMap[header]).Label, exit.Label }, - new List { blockMap[header], exit }); - - if (detLoopExtract) //cutting the non-determinism - cmd = new GotoCmd(Token.NoToken, - new List { cce.NonNull(blockMap[header]).Label }, - new List { blockMap[header] }); - - Block entry; - List initCmds = new List(); - if (loopHeaderToAssignCmd.ContainsKey(header)) { - AssignCmd assignCmd = loopHeaderToAssignCmd[header]; - initCmds.Add(assignCmd); - } - - entry = new Block(Token.NoToken, "entry", initCmds, cmd); - blocks.Add(entry); - - foreach (Block/*!*/ block in blockMap.Keys) { - Contract.Assert(block != null); - Block/*!*/ newBlock = cce.NonNull(blockMap[block]); - GotoCmd gotoCmd = block.TransferCmd as GotoCmd; - if (gotoCmd == null) { - newBlock.TransferCmd = new ReturnCmd(Token.NoToken); - } else { - Contract.Assume(gotoCmd.labelNames != null && gotoCmd.labelTargets != null); - List newLabels = new List(); - List newTargets = new List(); - for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { - Block target = gotoCmd.labelTargets[i]; - if (blockMap.ContainsKey(target)) { - newLabels.Add(gotoCmd.labelNames[i]); - newTargets.Add(blockMap[target]); - } - } - if (newTargets.Count == 0) { - if (!detLoopExtract) - newBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); - newBlock.TransferCmd = new ReturnCmd(Token.NoToken); - } else { - newBlock.TransferCmd = new GotoCmd(Token.NoToken, newLabels, newTargets); - } - } - blocks.Add(newBlock); - } - blocks.Add(exit); - Implementation loopImpl = - new Implementation(Token.NoToken, loopProc.Name, - new List(), inputs, outputs, new List(), blocks); - loopImpl.Proc = loopProc; - loopImpls.Add(loopImpl); - - // Make a (shallow) copy of the header before splitting it - Block origHeader = new Block(header.tok, header.Label, header.Cmds, header.TransferCmd); - - // Finally, add call to the loop in the containing procedure - string lastIterBlockName = header.Label + "_last"; - Block lastIterBlock = new Block(Token.NoToken, lastIterBlockName, header.Cmds, header.TransferCmd); - newBlocksCreated[header] = lastIterBlock; - header.Cmds = new List { loopHeaderToCallCmd1[header] }; - header.TransferCmd = new GotoCmd(Token.NoToken, new List { lastIterBlockName }, new List { lastIterBlock }); - impl.Blocks.Add(lastIterBlock); - blockMap[origHeader] = blockMap[header]; - blockMap.Remove(header); - - Contract.Assert(fullMap[impl.Name][header.Label] == header); - fullMap[impl.Name][header.Label] = origHeader; - - foreach (Block block in blockMap.Keys) - { - // Don't add dummy blocks to the map - if (dummyBlocks.Contains(blockMap[block].Label)) continue; - - // Following two statements are for nested loops: compose map - if (!fullMap[impl.Name].ContainsKey(block.Label)) continue; - var target = fullMap[impl.Name][block.Label]; - - AddToFullMap(fullMap, loopProc.Name, blockMap[block].Label, target); - } - - fullMap[impl.Name].Remove(header.Label); - fullMap[impl.Name][lastIterBlockName] = origHeader; - } - } - - private void addUniqueCallAttr(int val, CallCmd cmd) - { - var a = new List(); - a.Add(new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(val))); - - cmd.Attributes = new QKeyValue(Token.NoToken, "si_unique_call", a, cmd.Attributes); - } - - private void AddToFullMap(Dictionary> fullMap, string procName, string blockName, Block block) - { - if (!fullMap.ContainsKey(procName)) - fullMap[procName] = new Dictionary(); - fullMap[procName][blockName] = block; - } - - public static Graph BuildCallGraph(Program program) { - Graph callGraph = new Graph(); - Dictionary> procToImpls = new Dictionary>(); - foreach (var proc in program.Procedures) { - procToImpls[proc] = new HashSet(); - } - foreach (var impl in program.Implementations) { - if (impl.SkipVerification) continue; - callGraph.AddSource(impl); - procToImpls[impl.Proc].Add(impl); - } - foreach (var impl in program.Implementations) { - if (impl.SkipVerification) continue; - foreach (Block b in impl.Blocks) { - foreach (Cmd c in b.Cmds) { - CallCmd cc = c as CallCmd; - if (cc == null) continue; - foreach (Implementation callee in procToImpls[cc.Proc]) { - callGraph.AddEdge(impl, callee); - } - } - } - } - return callGraph; - } - - public static Graph/*!*/ GraphFromImpl(Implementation impl) { - Contract.Requires(impl != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>().Nodes)); - Contract.Ensures(Contract.Result>() != null); - - Graph g = new Graph(); - g.AddSource(impl.Blocks[0]); // there is always at least one node in the graph - - foreach (Block b in impl.Blocks) { - Contract.Assert(b != null); - GotoCmd gtc = b.TransferCmd as GotoCmd; - if (gtc != null) { - foreach (Block/*!*/ dest in cce.NonNull(gtc.labelTargets)) { - Contract.Assert(dest != null); - g.AddEdge(b, dest); - } - } - } - return g; - } - - public class IrreducibleLoopException : Exception {} - - public Graph ProcessLoops(Implementation impl) { - while (true) { - impl.PruneUnreachableBlocks(); - impl.ComputePredecessorsForBlocks(); - Graph/*!*/ g = GraphFromImpl(impl); - g.ComputeLoops(); - if (g.Reducible) { - return g; - } - throw new IrreducibleLoopException(); -#if USED_CODE - System.Diagnostics.Debug.Assert(g.SplitCandidates.Count > 0); - Block splitCandidate = null; - foreach (Block b in g.SplitCandidates) { - if (b.Predecessors.Length > 1) { - splitCandidate = b; - break; - } - } - System.Diagnostics.Debug.Assert(splitCandidate != null); - int count = 0; - foreach (Block b in splitCandidate.Predecessors) { - GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; - gotoCmd.labelNames.Remove(splitCandidate.Label); - gotoCmd.labelTargets.Remove(splitCandidate); - - CodeCopier codeCopier = new CodeCopier(new Hashtable(), new Hashtable()); - List newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds); - TransferCmd newTransferCmd; - GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd; - if (splitGotoCmd == null) { - newTransferCmd = new ReturnCmd(splitCandidate.tok); - } - else { - List newLabelNames = new List(); - newLabelNames.AddRange(splitGotoCmd.labelNames); - List newLabelTargets = new List(); - newLabelTargets.AddRange(splitGotoCmd.labelTargets); - newTransferCmd = new GotoCmd(splitCandidate.tok, newLabelNames, newLabelTargets); - } - Block copy = new Block(splitCandidate.tok, splitCandidate.Label + count++, newCmdSeq, newTransferCmd); - - impl.Blocks.Add(copy); - gotoCmd.AddTarget(copy); - } -#endif - } - } - - public Dictionary> ExtractLoops() - { - HashSet procsWithIrreducibleLoops = null; - return ExtractLoops(out procsWithIrreducibleLoops); - } - - public Dictionary> ExtractLoops(out HashSet procsWithIrreducibleLoops) - { - procsWithIrreducibleLoops = new HashSet(); - List/*!*/ loopImpls = new List(); - Dictionary> fullMap = new Dictionary>(); - foreach (var impl in this.Implementations) - { - if (impl.Blocks != null && impl.Blocks.Count > 0) - { - try - { - Graph g = ProcessLoops(impl); - CreateProceduresForLoops(impl, g, loopImpls, fullMap); - } - catch (IrreducibleLoopException) - { - System.Diagnostics.Debug.Assert(!fullMap.ContainsKey(impl.Name)); - fullMap[impl.Name] = null; - procsWithIrreducibleLoops.Add(impl.Name); - - if (CommandLineOptions.Clo.ExtractLoopsUnrollIrreducible) - { - // statically unroll loops in this procedure - - // First, build a map of the current blocks - var origBlocks = new Dictionary(); - foreach (var blk in impl.Blocks) origBlocks.Add(blk.Label, blk); - - // unroll - Block start = impl.Blocks[0]; - impl.Blocks = LoopUnroll.UnrollLoops(start, CommandLineOptions.Clo.RecursionBound, false); - - // Now construct the "map back" information - // Resulting block label -> original block - var blockMap = new Dictionary(); - foreach (var blk in impl.Blocks) - { - var sl = LoopUnroll.sanitizeLabel(blk.Label); - if (sl == blk.Label) blockMap.Add(blk.Label, blk); - else - { - Contract.Assert(origBlocks.ContainsKey(sl)); - blockMap.Add(blk.Label, origBlocks[sl]); - } - } - fullMap[impl.Name] = blockMap; - } - } - } - } - foreach (Implementation/*!*/ loopImpl in loopImpls) - { - Contract.Assert(loopImpl != null); - AddTopLevelDeclaration(loopImpl); - AddTopLevelDeclaration(loopImpl.Proc); - } - return fullMap; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitProgram(this); - } - - int extractedFunctionCount; - public string FreshExtractedFunctionName() - { - var c = System.Threading.Interlocked.Increment(ref extractedFunctionCount); - return string.Format("##extracted_function##{0}", c); - } - - private int invariantGenerationCounter = 0; - - public Constant MakeExistentialBoolean() { - Constant ExistentialBooleanConstant = new Constant(Token.NoToken, new TypedIdent(tok, "_b" + invariantGenerationCounter, Microsoft.Boogie.Type.Bool), false); - invariantGenerationCounter++; - ExistentialBooleanConstant.AddAttribute("existential", new object[] { Expr.True }); - AddTopLevelDeclaration(ExistentialBooleanConstant); - return ExistentialBooleanConstant; - } - - public PredicateCmd CreateCandidateInvariant(Expr e, string tag = null) { - Constant ExistentialBooleanConstant = MakeExistentialBoolean(); - IdentifierExpr ExistentialBoolean = new IdentifierExpr(Token.NoToken, ExistentialBooleanConstant); - PredicateCmd invariant = new AssertCmd(Token.NoToken, Expr.Imp(ExistentialBoolean, e)); - if (tag != null) - invariant.Attributes = new QKeyValue(Token.NoToken, "tag", new List(new object[] { tag }), null); - return invariant; - } - } - - //--------------------------------------------------------------------- - // Declarations - - [ContractClass(typeof(DeclarationContracts))] - public abstract class Declaration : Absy { - public QKeyValue Attributes; - - public Declaration(IToken tok) - : base(tok) { - Contract.Requires(tok != null); - } - - protected void EmitAttributes(TokenTextWriter stream) { - Contract.Requires(stream != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Emit(stream); - stream.Write(" "); - } - } - - protected void ResolveAttributes(ResolutionContext rc) { - Contract.Requires(rc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Resolve(rc); - } - } - - protected void TypecheckAttributes(TypecheckingContext rc) { - Contract.Requires(rc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Typecheck(rc); - } - } - - /// - /// If the declaration has an attribute {:name} or {:name true}, then set "result" to "true" and return "true". - /// If the declaration has an attribute {:name false}, then set "result" to "false" and return "true". - /// Otherwise, return "false" and leave "result" unchanged (which gives the caller an easy way to indicate - /// a default value if the attribute is not mentioned). - /// If there is more than one attribute called :name, then the last attribute rules. - /// - public bool CheckBooleanAttribute(string name, ref bool result) { - Contract.Requires(name != null); - var kv = FindAttribute(name); - if (kv != null) { - if (kv.Params.Count == 0) { - result = true; - return true; - } else if (kv.Params.Count == 1) { - var lit = kv.Params[0] as LiteralExpr; - if (lit != null && lit.isBool) { - result = lit.asBool; - return true; - } - } - } - return false; - } - - /// - /// Find and return the last occurrence of an attribute with the name "name", if any. If none, return null. - /// - public QKeyValue FindAttribute(string name) { - Contract.Requires(name != null); - QKeyValue res = null; - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - if (kv.Key == name) { - res = kv; - } - } - return res; - } - - // Look for {:name expr} in list of attributes. - public Expr FindExprAttribute(string name) { - Contract.Requires(name != null); - Expr res = null; - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - if (kv.Key == name) { - if (kv.Params.Count == 1 && kv.Params[0] is Expr) { - res = (Expr)kv.Params[0]; - } - } - } - return res; - } - - // Look for {:name string} in list of attributes. - public string FindStringAttribute(string name) { - Contract.Requires(name != null); - return QKeyValue.FindStringAttribute(this.Attributes, name); - } - - // Look for {:name N} or {:name N} in list of attributes. Return result in 'result' - // (which is not touched if there is no attribute specified). - // - // Returns false is there was an error processing the flag, true otherwise. - public bool CheckIntAttribute(string name, ref int result) { - Contract.Requires(name != null); - Expr expr = FindExprAttribute(name); - if (expr != null) { - if (expr is LiteralExpr && ((LiteralExpr)expr).isBigNum) { - result = ((LiteralExpr)expr).asBigNum.ToInt; - } else { - return false; - } - } - return true; - } - - public void AddAttribute(string name, params object[] vals) { - Contract.Requires(name != null); - QKeyValue kv; - for (kv = this.Attributes; kv != null; kv = kv.Next) { - if (kv.Key == name) { - kv.AddParams(vals); - break; - } - } - if (kv == null) { - Attributes = new QKeyValue(tok, name, new List(vals), Attributes); - } - } - - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - public abstract void Register(ResolutionContext/*!*/ rc); - - /// - /// Compute the strongly connected components of the declaration. - /// By default, it does nothing - /// - public virtual void ComputeStronglyConnectedComponents() { /* Does nothing */ - } - - /// - /// Reset the abstract stated computed before - /// - public virtual void ResetAbstractInterpretationState() { /* does nothing */ - } - } - [ContractClassFor(typeof(Declaration))] - public abstract class DeclarationContracts : Declaration { - public DeclarationContracts() :base(null){ - } - public override void Register(ResolutionContext rc) { - Contract.Requires(rc != null); - throw new NotImplementedException(); - } - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - } - - public class Axiom : Declaration { - private Expr/*!*/ expression; - - public Expr Expr { - get { - Contract.Ensures(Contract.Result() != null); - return this.expression; - } - set { - Contract.Requires(value != null); - this.expression = value; - } - } - - [ContractInvariantMethod] - void ExprInvariant() { - Contract.Invariant(this.expression != null); - } - - public string Comment; - - public Axiom(IToken tok, Expr expr) - : this(tok, expr, null) { - Contract.Requires(expr != null); - Contract.Requires(tok != null); - } - - public Axiom(IToken/*!*/ tok, Expr/*!*/ expr, string comment) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - this.expression = expr; - Comment = comment; - } - - public Axiom(IToken tok, Expr expr, string comment, QKeyValue kv) - : this(tok, expr, comment) { - Contract.Requires(expr != null); - Contract.Requires(tok != null); - this.Attributes = kv; - } - - public bool DependenciesCollected { get; set; } - - ISet functionDependencies; - - public ISet FunctionDependencies - { - get { return functionDependencies; } - } - - public void AddFunctionDependency(Function function) - { - Contract.Requires(function != null); - - if (functionDependencies == null) - { - functionDependencies = new HashSet(); - } - functionDependencies.Add(function); - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "axiom "); - EmitAttributes(stream); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddAxiom(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(rc); - rc.StateMode = ResolutionContext.State.StateLess; - Expr.Resolve(rc); - rc.StateMode = ResolutionContext.State.Single; - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from postcondition of Expr.Typecheck - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "axioms must be of type bool"); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAxiom(this); - } - } - - public abstract class NamedDeclaration : Declaration { - private string/*!*/ name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(name != null); - } - - public string/*!*/ Name { - get { - Contract.Ensures(Contract.Result() != null); - - return this.name; - } - set { - Contract.Requires(value != null); - this.name = value; - } - } - - public int TimeLimit - { - get - { - int tl = CommandLineOptions.Clo.ProverKillTime; - CheckIntAttribute("timeLimit", ref tl); - return tl; - } - } - - public NamedDeclaration(IToken/*!*/ tok, string/*!*/ name) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - this.name = name; - } - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(Name); - } - } - - public class TypeCtorDecl : NamedDeclaration { - public readonly int Arity; - - public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - this.Arity = Arity; - } - public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity, QKeyValue kv) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - this.Arity = Arity; - this.Attributes = kv; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "type "); - EmitAttributes(stream); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); - for (int i = 0; i < Arity; ++i) - stream.Write(" _"); - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddType(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(rc); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeCtorDecl(this); - } - } - - public class TypeSynonymDecl : NamedDeclaration { - private List/*!*/ typeParameters; - - public List TypeParameters { - get { - Contract.Ensures(Contract.Result>() != null); - return this.typeParameters; - } - set { - Contract.Requires(value != null); - this.typeParameters = value; - } - } - - private Type/*!*/ body; - - public Type Body { - get { - Contract.Ensures(Contract.Result() != null); - return this.body; - } - set { - Contract.Requires(value != null); - this.body = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.body != null); - Contract.Invariant(this.typeParameters != null); - } - - public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, - List/*!*/ typeParams, Type/*!*/ body) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(body != null); - this.typeParameters = typeParams; - this.body = body; - } - public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, - List/*!*/ typeParams, Type/*!*/ body, QKeyValue kv) - : base(tok, name) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(body != null); - this.typeParameters = typeParams; - this.body = body; - this.Attributes = kv; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "type "); - EmitAttributes(stream); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); - if (TypeParameters.Count > 0) - stream.Write(" "); - TypeParameters.Emit(stream, " "); - stream.Write(" = "); - Body.Emit(stream); - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddType(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(rc); - - int previousState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - Body = Body.ResolveType(rc); - } finally { - rc.TypeBinderState = previousState; - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - } - - public static void ResolveTypeSynonyms(List/*!*/ synonymDecls, ResolutionContext/*!*/ rc) { - Contract.Requires(cce.NonNullElements(synonymDecls)); - Contract.Requires(rc != null); - // then discover all dependencies between type synonyms - IDictionary/*!*/>/*!*/ deps = - new Dictionary/*!*/>(); - foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { - Contract.Assert(decl != null); - List/*!*/ declDeps = new List(); - FindDependencies(decl.Body, declDeps, rc); - deps.Add(decl, declDeps); - } - - List/*!*/ resolved = new List(); - - int unresolved = synonymDecls.Count - resolved.Count; - while (unresolved > 0) { - foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { - Contract.Assert(decl != null); - if (!resolved.Contains(decl) && - deps[decl].All(d => resolved.Contains(d))) { - decl.Resolve(rc); - resolved.Add(decl); - } - } - - int newUnresolved = synonymDecls.Count - resolved.Count; - if (newUnresolved < unresolved) { - // we are making progress - unresolved = newUnresolved; - } else { - // there have to be cycles in the definitions - foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { - Contract.Assert(decl != null); - if (!resolved.Contains(decl)) { - rc.Error(decl, - "type synonym could not be resolved because of cycles: {0}" + - " (replacing body with \"bool\" to continue resolving)", - decl.Name); - - // we simply replace the bodies of all remaining type - // synonyms with "bool" so that resolution can continue - decl.Body = Type.Bool; - decl.Resolve(rc); - } - } - - unresolved = 0; - } - } - } - - // determine a list of all type synonyms that occur in "type" - private static void FindDependencies(Type/*!*/ type, List/*!*/ deps, ResolutionContext/*!*/ rc) { - Contract.Requires(type != null); - Contract.Requires(cce.NonNullElements(deps)); - Contract.Requires(rc != null); - if (type.IsVariable || type.IsBasic) { - // nothing - } else if (type.IsUnresolved) { - UnresolvedTypeIdentifier/*!*/ unresType = type.AsUnresolved; - Contract.Assert(unresType != null); - TypeSynonymDecl dep = rc.LookUpTypeSynonym(unresType.Name); - if (dep != null) - deps.Add(dep); - foreach (Type/*!*/ subtype in unresType.Arguments) { - Contract.Assert(subtype != null); - FindDependencies(subtype, deps, rc); - } - } else if (type.IsMap) { - MapType/*!*/ mapType = type.AsMap; - Contract.Assert(mapType != null); - foreach (Type/*!*/ subtype in mapType.Arguments) { - Contract.Assert(subtype != null); - FindDependencies(subtype, deps, rc); - } - FindDependencies(mapType.Result, deps, rc); - } else if (type.IsCtor) { - // this can happen because we allow types to be resolved multiple times - CtorType/*!*/ ctorType = type.AsCtor; - Contract.Assert(ctorType != null); - foreach (Type/*!*/ subtype in ctorType.Arguments) { - Contract.Assert(subtype != null); - FindDependencies(subtype, deps, rc); - } - } else { - System.Diagnostics.Debug.Fail("Did not expect this type during resolution: " - + type); - } - } - - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeSynonymDecl(this); - } - } - - public abstract class Variable : NamedDeclaration { - private TypedIdent/*!*/ typedIdent; - - public TypedIdent TypedIdent { - get { - Contract.Ensures(Contract.Result() != null); - return this.typedIdent; - } - set { - Contract.Requires(value != null); - this.typedIdent = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.typedIdent != null); - } - - public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) - : base(tok, typedIdent.Name) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - this.typedIdent = typedIdent; - } - - public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) - : base(tok, typedIdent.Name) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - this.typedIdent = typedIdent; - this.Attributes = kv; - } - - public abstract bool IsMutable { - get; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "var "); - EmitVitals(stream, level, true); - stream.WriteLine(";"); - } - public void EmitVitals(TokenTextWriter stream, int level, bool emitAttributes) { - Contract.Requires(stream != null); - if (emitAttributes) { - EmitAttributes(stream); - } - if (CommandLineOptions.Clo.PrintWithUniqueASTIds && this.TypedIdent.HasName) { - stream.Write("h{0}^^", this.GetHashCode()); // the idea is that this will prepend the name printed by TypedIdent.Emit - } - this.TypedIdent.Emit(stream); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - this.TypedIdent.Resolve(rc); - } - public void ResolveWhere(ResolutionContext rc) { - Contract.Requires(rc != null); - if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && this.TypedIdent.WhereExpr != null) - { - rc.Error(tok, "assumption variable may not be declared with a where clause"); - } - if (this.TypedIdent.WhereExpr != null) { - this.TypedIdent.WhereExpr.Resolve(rc); - } - ResolveAttributes(rc); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - this.TypedIdent.Typecheck(tc); - if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && !this.TypedIdent.Type.IsBool) - { - tc.Error(tok, "assumption variable must be of type 'bool'"); - } - } - } - - public class VariableComparer : IComparer { - public int Compare(object a, object b) { - Variable A = a as Variable; - Variable B = b as Variable; - if (A == null || B == null) { - throw new ArgumentException("VariableComparer works only on objects of type Variable"); - } - return cce.NonNull(A.Name).CompareTo(B.Name); - } - } - - // class to specify the <:-parents of the values of constants - public class ConstantParent { - public readonly IdentifierExpr/*!*/ Parent; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Parent != null); - } - - // if true, the sub-dag underneath this constant-parent edge is - // disjoint from all other unique sub-dags - public readonly bool Unique; - - public ConstantParent(IdentifierExpr parent, bool unique) { - Contract.Requires(parent != null); - Parent = parent; - Unique = unique; - } - } - - public class Constant : Variable { - // when true, the value of this constant is meant to be distinct - // from all other constants. - public readonly bool Unique; - - // the <:-parents of the value of this constant. If the field is - // null, no information about the parents is provided, which means - // that the parental situation is unconstrained. - public readonly ReadOnlyCollection Parents; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(Parents, true)); - } - - // if true, it is assumed that the immediate <:-children of the - // value of this constant are completely specified - public readonly bool ChildrenComplete; - - public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) - : base(tok, typedIdent) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - Contract.Requires(typedIdent.Name != null && (!typedIdent.HasName || typedIdent.Name.Length > 0)); - Contract.Requires(typedIdent.WhereExpr == null); - this.Unique = true; - this.Parents = null; - this.ChildrenComplete = false; - } - public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, bool unique) - : base(tok, typedIdent) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); - Contract.Requires(typedIdent.WhereExpr == null); - this.Unique = unique; - this.Parents = null; - this.ChildrenComplete = false; - } - public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, - bool unique, - IEnumerable parents, bool childrenComplete, - QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - Contract.Requires(cce.NonNullElements(parents, true)); - Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); - Contract.Requires(typedIdent.WhereExpr == null); - this.Unique = unique; - this.Parents = parents == null ? null : new ReadOnlyCollection(parents.ToList()); - this.ChildrenComplete = childrenComplete; - } - public override bool IsMutable { - get { - return false; - } - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "const "); - EmitAttributes(stream); - if (this.Unique) { - stream.Write(this, level, "unique "); - } - EmitVitals(stream, level, false); - - if (Parents != null || ChildrenComplete) { - stream.Write(this, level, " extends"); - string/*!*/ sep = " "; - foreach (ConstantParent/*!*/ p in cce.NonNull(Parents)) { - Contract.Assert(p != null); - stream.Write(this, level, sep); - sep = ", "; - if (p.Unique) - stream.Write(this, level, "unique "); - p.Parent.Emit(stream); - } - if (ChildrenComplete) - stream.Write(this, level, " complete"); - } - - stream.WriteLine(";"); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, true); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - base.Resolve(rc); - if (Parents != null) { - foreach (ConstantParent/*!*/ p in Parents) { - Contract.Assert(p != null); - p.Parent.Resolve(rc); - if (p.Parent.Decl != null && !(p.Parent.Decl is Constant)) - rc.Error(p.Parent, "the parent of a constant has to be a constant"); - if (this.Equals(p.Parent.Decl)) - rc.Error(p.Parent, "constant cannot be its own parent"); - } - } - - // check that no parent occurs twice - // (could be optimised) - if (Parents != null) { - for (int i = 0; i < Parents.Count; ++i) { - if (Parents[i].Parent.Decl != null) { - for (int j = i + 1; j < Parents.Count; ++j) { - if (Parents[j].Parent.Decl != null && - cce.NonNull(Parents[i].Parent.Decl).Equals(Parents[j].Parent.Decl)) - rc.Error(Parents[j].Parent, - "{0} occurs more than once as parent", - Parents[j].Parent.Decl); - } - } - } - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - base.Typecheck(tc); - - if (Parents != null) { - foreach (ConstantParent/*!*/ p in Parents) { - Contract.Assert(p != null); - p.Parent.Typecheck(tc); - if (!cce.NonNull(p.Parent.Decl).TypedIdent.Type.Unify(this.TypedIdent.Type)) - tc.Error(p.Parent, - "parent of constant has incompatible type ({0} instead of {1})", - p.Parent.Decl.TypedIdent.Type, this.TypedIdent.Type); - } - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitConstant(this); - } - } - public class GlobalVariable : Variable { - public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) - : base(tok, typedIdent) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - } - public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(tok != null); - Contract.Requires(typedIdent != null); - } - public override bool IsMutable { - get { - return true; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, true); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitGlobalVariable(this); - } - } - public class Formal : Variable { - public bool InComing; - public Formal(IToken tok, TypedIdent typedIdent, bool incoming, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - InComing = incoming; - } - public Formal(IToken tok, TypedIdent typedIdent, bool incoming) - : this(tok, typedIdent, incoming, null) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - } - public override bool IsMutable { - get { - return !InComing; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, false); - } - - /// - /// Given a sequence of Formal declarations, returns sequence of Formals like the given one but without where clauses - /// and without any attributes. - /// The Type of each Formal is cloned. - /// - public static List StripWhereClauses(List w) { - Contract.Requires(w != null); - Contract.Ensures(Contract.Result>() != null); - List s = new List(); - foreach (Variable/*!*/ v in w) { - Contract.Assert(v != null); - Formal f = (Formal)v; - TypedIdent ti = f.TypedIdent; - s.Add(new Formal(f.tok, new TypedIdent(ti.tok, ti.Name, ti.Type.CloneUnresolved()), f.InComing, null)); - } - return s; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitFormal(this); - } - } - public class LocalVariable : Variable { - public LocalVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - } - public LocalVariable(IToken tok, TypedIdent typedIdent) - : base(tok, typedIdent, null) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - } - public override bool IsMutable { - get { - return true; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, false); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitLocalVariable(this); - } - } - public class Incarnation : LocalVariable { - public int incarnationNumber; - public Incarnation(Variable/*!*/ var, int i) : - base( - var.tok, - new TypedIdent(var.TypedIdent.tok, var.TypedIdent.Name + "@" + i, var.TypedIdent.Type) - ) { - Contract.Requires(var != null); - incarnationNumber = i; - } - - } - public class BoundVariable : Variable { - public BoundVariable(IToken tok, TypedIdent typedIdent) - : base(tok, typedIdent) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - Contract.Requires(typedIdent.WhereExpr == null); - } - public BoundVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) - : base(tok, typedIdent, kv) { - Contract.Requires(typedIdent != null); - Contract.Requires(tok != null); - Contract.Requires(typedIdent.WhereExpr == null); - } - public override bool IsMutable { - get { - return false; - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddVariable(this, false); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBoundVariable(this); - } - } - - public abstract class DeclWithFormals : NamedDeclaration { - public List/*!*/ TypeParameters; - - private /*readonly--except in StandardVisitor*/ List/*!*/ inParams, outParams; - - public List/*!*/ InParams { - get { - Contract.Ensures(Contract.Result>() != null); - return this.inParams; - } - set { - Contract.Requires(value != null); - this.inParams = value; - } - } - - public List/*!*/ OutParams - { - get { - Contract.Ensures(Contract.Result>() != null); - return this.outParams; - } - set { - Contract.Requires(value != null); - this.outParams = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(TypeParameters != null); - Contract.Invariant(this.inParams != null); - Contract.Invariant(this.outParams != null); - } - - public DeclWithFormals(IToken tok, string name, List typeParams, - List inParams, List outParams) - : base(tok, name) { - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - this.TypeParameters = typeParams; - this.inParams = inParams; - this.outParams = outParams; - } - - protected DeclWithFormals(DeclWithFormals that) - : base(that.tok, cce.NonNull(that.Name)) { - Contract.Requires(that != null); - this.TypeParameters = that.TypeParameters; - this.inParams = cce.NonNull(that.InParams); - this.outParams = cce.NonNull(that.OutParams); - } - - public byte[] MD5Checksum_; - public byte[] MD5Checksum - { - get - { - if (MD5Checksum_ == null) - { - var c = Checksum; - if (c != null) - { - MD5Checksum_ = System.Security.Cryptography.MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(c)); - } - } - return MD5Checksum_; - } - } - - public byte[] MD5DependencyChecksum_; - public byte[] MD5DependencyChecksum - { - get - { - Contract.Requires(DependenciesCollected); - - if (MD5DependencyChecksum_ == null && MD5Checksum != null) - { - var c = MD5Checksum; - var transFuncDeps = new HashSet(); - if (procedureDependencies != null) - { - foreach (var p in procedureDependencies) - { - if (p.FunctionDependencies != null) - { - foreach (var f in p.FunctionDependencies) - { - transFuncDeps.Add(f); - } - } - var pc = p.MD5Checksum; - if (pc == null) { return null; } - c = ChecksumHelper.CombineChecksums(c, pc, true); - } - } - if (FunctionDependencies != null) - { - foreach (var f in FunctionDependencies) - { - transFuncDeps.Add(f); - } - } - var q = new Queue(transFuncDeps); - while (q.Any()) - { - var f = q.Dequeue(); - var fc = f.MD5Checksum; - if (fc == null) { return null; } - c = ChecksumHelper.CombineChecksums(c, fc, true); - if (f.FunctionDependencies != null) - { - foreach (var d in f.FunctionDependencies) - { - if (!transFuncDeps.Contains(d)) - { - transFuncDeps.Add(d); - q.Enqueue(d); - } - } - } - } - MD5DependencyChecksum_ = c; - } - return MD5DependencyChecksum_; - } - } - - public string Checksum - { - get - { - return FindStringAttribute("checksum"); - } - } - - string dependencyChecksum; - public string DependencyChecksum - { - get - { - if (dependencyChecksum == null && DependenciesCollected && MD5DependencyChecksum != null) - { - dependencyChecksum = BitConverter.ToString(MD5DependencyChecksum); - } - return dependencyChecksum; - } - } - - public bool DependenciesCollected { get; set; } - - ISet procedureDependencies; - - public ISet ProcedureDependencies - { - get { return procedureDependencies; } - } - - public void AddProcedureDependency(Procedure procedure) - { - Contract.Requires(procedure != null); - - if (procedureDependencies == null) - { - procedureDependencies = new HashSet(); - } - procedureDependencies.Add(procedure); - } - - ISet functionDependencies; - - public ISet FunctionDependencies - { - get { return functionDependencies; } - } - - public void AddFunctionDependency(Function function) - { - Contract.Requires(function != null); - - if (functionDependencies == null) - { - functionDependencies = new HashSet(); - } - functionDependencies.Add(function); - } - - public bool SignatureEquals(DeclWithFormals other) - { - Contract.Requires(other != null); - - string sig = null; - string otherSig = null; - using (var strWr = new System.IO.StringWriter()) - using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) - { - EmitSignature(tokTxtWr, this is Function); - sig = strWr.ToString(); - } - - using (var otherStrWr = new System.IO.StringWriter()) - using (var otherTokTxtWr = new TokenTextWriter("", otherStrWr, false, false)) - { - EmitSignature(otherTokTxtWr, other is Function); - otherSig = otherStrWr.ToString(); - } - return sig == otherSig; - } - - protected void EmitSignature(TokenTextWriter stream, bool shortRet) { - Contract.Requires(stream != null); - Type.EmitOptionalTypeParams(stream, TypeParameters); - stream.Write("("); - stream.push(); - InParams.Emit(stream, true); - stream.Write(")"); - stream.sep(); - - if (shortRet) { - Contract.Assert(OutParams.Count == 1); - stream.Write(" : "); - cce.NonNull(OutParams[0]).TypedIdent.Type.Emit(stream); - } else if (OutParams.Count > 0) { - stream.Write(" returns ("); - OutParams.Emit(stream, true); - stream.Write(")"); - } - stream.pop(); - } - - // Register all type parameters at the resolution context - protected void RegisterTypeParameters(ResolutionContext rc) { - Contract.Requires(rc != null); - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - } - - protected void SortTypeParams() { - List/*!*/ allTypes = new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()); - Contract.Assert(allTypes != null); - allTypes.AddRange(new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray())); - TypeParameters = Type.SortTypeParams(TypeParameters, allTypes, null); - } - - /// - /// Adds the given formals to the current variable context, and then resolves - /// the types of those formals. Does NOT resolve the where clauses of the - /// formals. - /// Relies on the caller to first create, and later tear down, that variable - /// context. - /// - /// - protected void RegisterFormals(List formals, ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Requires(formals != null); - foreach (Formal/*!*/ f in formals) { - Contract.Assert(f != null); - if (f.Name != TypedIdent.NoName) { - rc.AddVariable(f, false); - } - f.Resolve(rc); - } - } - - /// - /// Resolves the where clauses (and attributes) of the formals. - /// - /// - protected void ResolveFormals(List formals, ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Requires(formals != null); - foreach (Formal/*!*/ f in formals) { - Contract.Assert(f != null); - f.ResolveWhere(rc); - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(tc); - foreach (Formal/*!*/ p in InParams) { - Contract.Assert(p != null); - p.Typecheck(tc); - } - foreach (Formal/*!*/ p in OutParams) { - Contract.Assert(p != null); - p.Typecheck(tc); - } - } - } - - public class DatatypeConstructor : Function { - public List selectors; - public DatatypeMembership membership; - - public DatatypeConstructor(Function func) - : base(func.tok, func.Name, func.TypeParameters, func.InParams, func.OutParams[0], func.Comment, func.Attributes) - { - selectors = new List(); - } - - public override void Resolve(ResolutionContext rc) { - HashSet selectorNames = new HashSet(); - foreach (DatatypeSelector selector in selectors) { - if (selector.Name.StartsWith("#")) { - rc.Error(selector.tok, "The selector must be a non-empty string"); - } - else { - if (selectorNames.Contains(selector.Name)) - rc.Error(this.tok, "The selectors for a constructor must be distinct strings"); - else - selectorNames.Add(selector.Name); - } - } - base.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - CtorType outputType = this.OutParams[0].TypedIdent.Type as CtorType; - if (outputType == null || !outputType.IsDatatype()) { - tc.Error(tok, "The output type of a constructor must be a datatype"); - } - base.Typecheck(tc); - } - } - - public class DatatypeSelector : Function { - public Function constructor; - public int index; - public DatatypeSelector(Function constructor, int index) - : base(constructor.InParams[index].tok, - constructor.InParams[index].Name + "#" + constructor.Name, - new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, - new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.InParams[index].TypedIdent.Type), false)) - { - this.constructor = constructor; - this.index = index; - } - - public override void Emit(TokenTextWriter stream, int level) { } - } - - public class DatatypeMembership : Function { - public Function constructor; - public DatatypeMembership(Function constructor) - : base(constructor.tok, - "is#" + constructor.Name, - new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, - new Formal(constructor.tok, new TypedIdent(constructor.tok, "", Type.Bool), false)) - { - this.constructor = constructor; - } - - public override void Emit(TokenTextWriter stream, int level) { } - } - - public class Function : DeclWithFormals { - public string Comment; - - // the body is only set if the function is declared with {:inline} - public Expr Body; - public Axiom DefinitionAxiom; - - public IList otherDefinitionAxioms; - public IEnumerable OtherDefinitionAxioms - { - get - { - return otherDefinitionAxioms; - } - } - - public void AddOtherDefinitionAxiom(Axiom axiom) - { - Contract.Requires(axiom != null); - - if (otherDefinitionAxioms == null) - { - otherDefinitionAxioms = new List(); - } - otherDefinitionAxioms.Add(axiom); - } - - public bool doingExpansion; - - private bool neverTrigger; - private bool neverTriggerComputed; - - public string OriginalLambdaExprAsString; - - public Function(IToken tok, string name, List args, Variable result) - : this(tok, name, new List(), args, result, null) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, new List(), args, result, null); - } - public Function(IToken tok, string name, List typeParams, List args, Variable result) - : this(tok, name, typeParams, args, result, null) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, args, result, null); - } - public Function(IToken tok, string name, List args, Variable result, string comment) - : this(tok, name, new List(), args, result, comment) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, new List(), args, result, comment); - } - public Function(IToken tok, string name, List typeParams, List args, Variable/*!*/ result, string comment) - : base(tok, name, typeParams, args, new List { result }) { - Contract.Requires(result != null); - Contract.Requires(args != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - Comment = comment; - } - public Function(IToken tok, string name, List typeParams, List args, Variable result, - string comment, QKeyValue kv) - : this(tok, name, typeParams, args, result, comment) { - Contract.Requires(args != null); - Contract.Requires(result != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, args, result, comment); - this.Attributes = kv; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "function "); - EmitAttributes(stream); - if (Body != null && !QKeyValue.FindBoolAttribute(Attributes, "inline")) { - // Boogie inlines any function whose .Body field is non-null. The parser populates the .Body field - // is the :inline attribute is present, but if someone creates the Boogie file directly as an AST, then - // the :inline attribute may not be there. We'll make sure it's printed, so one can see that this means - // that the body will be inlined. - stream.Write("{:inline} "); - } - if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { - stream.Write("h{0}^^{1}", this.GetHashCode(), TokenTextWriter.SanitizeIdentifier(this.Name)); - } else { - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - EmitSignature(stream, true); - if (Body != null) { - stream.WriteLine(); - stream.WriteLine("{"); - stream.Write(level + 1, ""); - Body.Emit(stream); - stream.WriteLine(); - stream.WriteLine("}"); - } else { - stream.WriteLine(";"); - } - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddProcedure(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - int previousTypeBinderState = rc.TypeBinderState; - try { - RegisterTypeParameters(rc); - rc.PushVarContext(); - RegisterFormals(InParams, rc); - RegisterFormals(OutParams, rc); - ResolveAttributes(rc); - if (Body != null) - { - rc.StateMode = ResolutionContext.State.StateLess; - Body.Resolve(rc); - rc.StateMode = ResolutionContext.State.Single; - } - rc.PopVarContext(); - Type.CheckBoundVariableOccurrences(TypeParameters, - new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - this.tok, "function arguments", - rc); - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - SortTypeParams(); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - // PR: why was the base call left out previously? - base.Typecheck(tc); - // TypecheckAttributes(tc); - if (Body != null) { - Body.Typecheck(tc); - if (!cce.NonNull(Body.Type).Unify(cce.NonNull(OutParams[0]).TypedIdent.Type)) - tc.Error(Body, - "function body with invalid type: {0} (expected: {1})", - Body.Type, cce.NonNull(OutParams[0]).TypedIdent.Type); - } - } - - public bool NeverTrigger { - get { - if (!neverTriggerComputed) { - this.CheckBooleanAttribute("never_pattern", ref neverTrigger); - neverTriggerComputed = true; - } - return neverTrigger; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitFunction(this); - } - - public Axiom CreateDefinitionAxiom(Expr definition, QKeyValue kv = null) { - Contract.Requires(definition != null); - - List dummies = new List(); - List callArgs = new List(); - int i = 0; - foreach (Formal/*!*/ f in InParams) { - Contract.Assert(f != null); - string nm = f.TypedIdent.HasName ? f.TypedIdent.Name : "_" + i; - dummies.Add(new BoundVariable(f.tok, new TypedIdent(f.tok, nm, f.TypedIdent.Type))); - callArgs.Add(new IdentifierExpr(f.tok, nm)); - i++; - } - List/*!*/ quantifiedTypeVars = new List(); - foreach (TypeVariable/*!*/ t in TypeParameters) { - Contract.Assert(t != null); - quantifiedTypeVars.Add(new TypeVariable(tok, t.Name)); - } - - Expr call = new NAryExpr(tok, new FunctionCall(new IdentifierExpr(tok, Name)), callArgs); - // specify the type of the function, because it might be that - // type parameters only occur in the output type - call = Expr.CoerceType(tok, call, (Type)OutParams[0].TypedIdent.Type.Clone()); - Expr def = Expr.Binary(tok, BinaryOperator.Opcode.Eq, call, definition); - if (quantifiedTypeVars.Count != 0 || dummies.Count != 0) { - def = new ForallExpr(tok, quantifiedTypeVars, dummies, - kv, - new Trigger(tok, true, new List { call }, null), - def); - } - DefinitionAxiom = new Axiom(tok, def); - return DefinitionAxiom; - } - } - - public class Macro : Function { - public Macro(IToken tok, string name, List args, Variable result) - : base(tok, name, args, result) { } - } - - public class Requires : Absy, IPotentialErrorNode { - public readonly bool Free; - - private Expr/*!*/ _condition; - - public Expr/*!*/ Condition { - get { - Contract.Ensures(Contract.Result() != null); - return this._condition; - } - set { - Contract.Requires(value != null); - this._condition = value; - } - } - - public string Comment; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._condition != null); - } - - - // TODO: convert to use generics - private string errorData; - public string ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - - - private MiningStrategy errorDataEnhanced; - public MiningStrategy ErrorDataEnhanced { - get { - return errorDataEnhanced; - } - set { - errorDataEnhanced = value; - } - } - - public QKeyValue Attributes; - - public String ErrorMessage { - get { - return QKeyValue.FindStringAttribute(Attributes, "msg"); - } - } - - public Requires(IToken token, bool free, Expr condition, string comment, QKeyValue kv) - : base(token) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - this.Free = free; - this._condition = condition; - this.Comment = comment; - this.Attributes = kv; - } - - public Requires(IToken token, bool free, Expr condition, string comment) - : this(token, free, condition, comment, null) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - //:this(token, free, condition, comment, null); - } - - public Requires(bool free, Expr condition) - : this(Token.NoToken, free, condition, null) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, null); - } - - public Requires(bool free, Expr condition, string comment) - : this(Token.NoToken, free, condition, comment) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, comment); - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "{0}requires ", Free ? "free " : ""); - Cmd.EmitAttributes(stream, Attributes); - this.Condition.Emit(stream); - stream.WriteLine(";"); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - this.Condition.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - this.Condition.Typecheck(tc); - Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck - if (!this.Condition.Type.Unify(Type.Bool)) { - tc.Error(this, "preconditions must be of type bool"); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - return visitor.VisitRequires(this); - } - } - - public class Ensures : Absy, IPotentialErrorNode { - public readonly bool Free; - - private Expr/*!*/ _condition; - - public Expr/*!*/ Condition { - get { - Contract.Ensures(Contract.Result() != null); - return this._condition; - } - set { - Contract.Requires(value != null); - this._condition = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._condition != null); - } - - public string Comment; - - // TODO: convert to use generics - private string errorData; - public string ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - - private MiningStrategy errorDataEnhanced; - public MiningStrategy ErrorDataEnhanced { - get { - return errorDataEnhanced; - } - set { - errorDataEnhanced = value; - } - } - - public String ErrorMessage { - get { - return QKeyValue.FindStringAttribute(Attributes, "msg"); - } - } - - public QKeyValue Attributes; - - public Ensures(IToken token, bool free, Expr/*!*/ condition, string comment, QKeyValue kv) - : base(token) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - this.Free = free; - this._condition = condition; - this.Comment = comment; - this.Attributes = kv; - } - - public Ensures(IToken token, bool free, Expr condition, string comment) - : this(token, free, condition, comment, null) { - Contract.Requires(condition != null); - Contract.Requires(token != null); - //:this(token, free, condition, comment, null); - } - - public Ensures(bool free, Expr condition) - : this(Token.NoToken, free, condition, null) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, null); - } - - public Ensures(bool free, Expr condition, string comment) - : this(Token.NoToken, free, condition, comment) { - Contract.Requires(condition != null); - //:this(Token.NoToken, free, condition, comment); - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - if (Comment != null) { - stream.WriteLine(this, level, "// " + Comment); - } - stream.Write(this, level, "{0}ensures ", Free ? "free " : ""); - Cmd.EmitAttributes(stream, Attributes); - this.Condition.Emit(stream); - stream.WriteLine(";"); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - this.Condition.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - this.Condition.Typecheck(tc); - Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck - if (!this.Condition.Type.Unify(Type.Bool)) { - tc.Error(this, "postconditions must be of type bool"); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - return visitor.VisitEnsures(this); - } - } - - public class Procedure : DeclWithFormals { - public List/*!*/ Requires; - public List/*!*/ Modifies; - public List/*!*/ Ensures; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Requires != null); - Contract.Invariant(Modifies != null); - Contract.Invariant(Ensures != null); - Contract.Invariant(Summary != null); - } - - - // Abstract interpretation: Procedure-specific invariants... - [Rep] - public readonly ProcedureSummary/*!*/ Summary; - - public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, - List/*!*/ requires, List/*!*/ modifies, List/*!*/ ensures) - : this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(requires != null); - Contract.Requires(modifies != null); - Contract.Requires(ensures != null); - //:this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null); - } - - public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, - List/*!*/ @requires, List/*!*/ @modifies, List/*!*/ @ensures, QKeyValue kv - ) - : base(tok, name, typeParams, inParams, outParams) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(@requires != null); - Contract.Requires(@modifies != null); - Contract.Requires(@ensures != null); - this.Requires = @requires; - this.Modifies = @modifies; - this.Ensures = @ensures; - this.Summary = new ProcedureSummary(); - this.Attributes = kv; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "procedure "); - EmitAttributes(stream); - stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - EmitSignature(stream, false); - stream.WriteLine(";"); - - level++; - - foreach (Requires/*!*/ e in this.Requires) { - Contract.Assert(e != null); - e.Emit(stream, level); - } - - if (this.Modifies.Count > 0) { - stream.Write(level, "modifies "); - this.Modifies.Emit(stream, false); - stream.WriteLine(";"); - } - - foreach (Ensures/*!*/ e in this.Ensures) { - Contract.Assert(e != null); - e.Emit(stream, level); - } - - if (!CommandLineOptions.Clo.IntraproceduralInfer) { - for (int s = 0; s < this.Summary.Count; s++) { - ProcedureSummaryEntry/*!*/ entry = cce.NonNull(this.Summary[s]); - stream.Write(level + 1, "// "); - stream.WriteLine(); - } - } - - stream.WriteLine(); - stream.WriteLine(); - } - - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.AddProcedure(this); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.PushVarContext(); - - foreach (IdentifierExpr/*!*/ ide in Modifies) { - Contract.Assert(ide != null); - ide.Resolve(rc); - } - - int previousTypeBinderState = rc.TypeBinderState; - try { - RegisterTypeParameters(rc); - - RegisterFormals(InParams, rc); - ResolveFormals(InParams, rc); // "where" clauses of in-parameters are resolved without the out-parameters in scope - foreach (Requires/*!*/ e in Requires) { - Contract.Assert(e != null); - e.Resolve(rc); - } - RegisterFormals(OutParams, rc); - ResolveFormals(OutParams, rc); // "where" clauses of out-parameters are resolved with both in- and out-parametes in scope - - rc.StateMode = ResolutionContext.State.Two; - foreach (Ensures/*!*/ e in Ensures) { - Contract.Assert(e != null); - e.Resolve(rc); - } - rc.StateMode = ResolutionContext.State.Single; - ResolveAttributes(rc); - - Type.CheckBoundVariableOccurrences(TypeParameters, - new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - this.tok, "procedure arguments", - rc); - - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - - rc.PopVarContext(); - - SortTypeParams(); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - base.Typecheck(tc); - foreach (IdentifierExpr/*!*/ ide in Modifies) { - Contract.Assert(ide != null); - Contract.Assume(ide.Decl != null); - if (!ide.Decl.IsMutable) { - tc.Error(this, "modifies list contains constant: {0}", ide.Name); - } - ide.Typecheck(tc); - } - foreach (Requires/*!*/ e in Requires) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - bool oldYields = tc.Yields; - tc.Yields = QKeyValue.FindBoolAttribute(Attributes, "yields"); - foreach (Ensures/*!*/ e in Ensures) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - tc.Yields = oldYields; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitProcedure(this); - } - } - - public class LoopProcedure : Procedure - { - public Implementation enclosingImpl; - private Dictionary blockMap; - private Dictionary blockLabelMap; - - public LoopProcedure(Implementation impl, Block header, - List inputs, List outputs, List globalMods) - : base(Token.NoToken, impl.Name + "_loop_" + header.ToString(), - new List(), inputs, outputs, - new List(), globalMods, new List()) - { - enclosingImpl = impl; - } - - public void setBlockMap(Dictionary bm) - { - blockMap = bm; - blockLabelMap = new Dictionary(); - foreach (var kvp in bm) - { - blockLabelMap.Add(kvp.Key.Label, kvp.Value); - } - } - - public Block getBlock(string label) - { - if (blockLabelMap.ContainsKey(label)) return blockLabelMap[label]; - return null; - } - } - - public class Implementation : DeclWithFormals { - public List/*!*/ LocVars; - [Rep] - public StmtList StructuredStmts; - [Rep] - public List/*!*/ Blocks; - public Procedure Proc; - - // Blocks before applying passification etc. - // Both are used only when /inline is set. - public List OriginalBlocks; - public List OriginalLocVars; - - public readonly ISet AssertionChecksums = new HashSet(ChecksumComparer.Default); - - public sealed class ChecksumComparer : IEqualityComparer - { - static IEqualityComparer defaultComparer; - public static IEqualityComparer Default - { - get - { - if (defaultComparer == null) - { - defaultComparer = new ChecksumComparer(); - } - return defaultComparer; - } - } - - public bool Equals(byte[] x, byte[] y) - { - if (x == null || y == null) - { - return x == y; - } - else - { - return x.SequenceEqual(y); - } - } - - public int GetHashCode(byte[] checksum) - { - if (checksum == null) - { - throw new ArgumentNullException("checksum"); - } - else - { - var result = 17; - for (int i = 0; i < checksum.Length; i++) - { - result = result * 23 + checksum[i]; - } - return result; - } - } - } - - public void AddAssertionChecksum(byte[] checksum) - { - Contract.Requires(checksum != null); - - if (AssertionChecksums != null) - { - AssertionChecksums.Add(checksum); - } - } - - public ISet AssertionChecksumsInCachedSnapshot { get; set; } - - public bool IsAssertionChecksumInCachedSnapshot(byte[] checksum) - { - Contract.Requires(AssertionChecksumsInCachedSnapshot != null); - - return AssertionChecksumsInCachedSnapshot.Contains(checksum); - } - - public IList RecycledFailingAssertions { get; protected set; } - - public void AddRecycledFailingAssertion(AssertCmd assertion) - { - if (RecycledFailingAssertions == null) - { - RecycledFailingAssertions = new List(); - } - RecycledFailingAssertions.Add(assertion); - } - - public Cmd ExplicitAssumptionAboutCachedPrecondition { get; set; } - - // Strongly connected components - private StronglyConnectedComponents scc; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(LocVars != null); - Contract.Invariant(cce.NonNullElements(Blocks)); - Contract.Invariant(cce.NonNullElements(OriginalBlocks, true)); - Contract.Invariant(cce.NonNullElements(scc, true)); - - } - private bool BlockPredecessorsComputed; - public bool StronglyConnectedComponentsComputed { - get { - return this.scc != null; - } - } - - public bool SkipVerification { - get { - bool verify = true; - cce.NonNull(this.Proc).CheckBooleanAttribute("verify", ref verify); - this.CheckBooleanAttribute("verify", ref verify); - if (!verify) { - return true; - } - - if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assert || - CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assume) { - Expr inl = this.FindExprAttribute("inline"); - if (inl == null) - inl = this.Proc.FindExprAttribute("inline"); - if (inl != null && inl is LiteralExpr && ((LiteralExpr)inl).isBigNum && ((LiteralExpr)inl).asBigNum.Signum > 0) { - return true; - } - } - - if (CommandLineOptions.Clo.StratifiedInlining > 0) { - return !QKeyValue.FindBoolAttribute(Attributes, "entrypoint"); - } - - return false; - } - } - - public string Id - { - get - { - var id = FindStringAttribute("id"); - if (id == null) - { - id = Name + GetHashCode().ToString() + ":0"; - } - return id; - } - } - - public int Priority - { - get - { - int priority = 0; - CheckIntAttribute("priority", ref priority); - if (priority <= 0) - { - priority = 1; - } - return priority; - } - } - - public IDictionary ErrorChecksumToCachedError { get; private set; } - - public bool IsErrorChecksumInCachedSnapshot(byte[] checksum) - { - Contract.Requires(ErrorChecksumToCachedError != null); - - return ErrorChecksumToCachedError.ContainsKey(checksum); - } - - public void SetErrorChecksumToCachedError(IEnumerable> errors) - { - Contract.Requires(errors != null); - - ErrorChecksumToCachedError = new Dictionary(ChecksumComparer.Default); - foreach (var kv in errors) - { - ErrorChecksumToCachedError[kv.Item1] = kv.Item3; - if (kv.Item2 != null) - { - ErrorChecksumToCachedError[kv.Item2] = null; - } - } - } - - public bool HasCachedSnapshot - { - get - { - return ErrorChecksumToCachedError != null && AssertionChecksumsInCachedSnapshot != null; - } - } - - public bool AnyErrorsInCachedSnapshot - { - get - { - Contract.Requires(ErrorChecksumToCachedError != null); - - return ErrorChecksumToCachedError.Any(); - } - } - - IList injectedAssumptionVariables; - public IList InjectedAssumptionVariables - { - get - { - return injectedAssumptionVariables != null ? injectedAssumptionVariables : new List(); - } - } - - IList doomedInjectedAssumptionVariables; - public IList DoomedInjectedAssumptionVariables - { - get - { - return doomedInjectedAssumptionVariables != null ? doomedInjectedAssumptionVariables : new List(); - } - } - - public List RelevantInjectedAssumptionVariables(Dictionary incarnationMap) - { - return InjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); - } - - public List RelevantDoomedInjectedAssumptionVariables(Dictionary incarnationMap) - { - return DoomedInjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); - } - - public Expr ConjunctionOfInjectedAssumptionVariables(Dictionary incarnationMap, out bool isTrue) - { - Contract.Requires(incarnationMap != null); - - var vars = RelevantInjectedAssumptionVariables(incarnationMap).Select(v => incarnationMap[v]).ToList(); - isTrue = vars.Count == 0; - return LiteralExpr.BinaryTreeAnd(vars); - } - - public void InjectAssumptionVariable(LocalVariable variable, bool isDoomed = false) - { - LocVars.Add(variable); - if (isDoomed) - { - if (doomedInjectedAssumptionVariables == null) - { - doomedInjectedAssumptionVariables = new List(); - } - doomedInjectedAssumptionVariables.Add(variable); - } - else - { - if (injectedAssumptionVariables == null) - { - injectedAssumptionVariables = new List(); - } - injectedAssumptionVariables.Add(variable); - } - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, QKeyValue kv) - : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, kv, new Errors()) { - Contract.Requires(structuredStmts != null); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts) - : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()) { - Contract.Requires(structuredStmts != null); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, Errors errorHandler) - : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler) { - Contract.Requires(errorHandler != null); - Contract.Requires(structuredStmts != null); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler); - } - - public Implementation(IToken/*!*/ tok, - string/*!*/ name, - List/*!*/ typeParams, - List/*!*/ inParams, - List/*!*/ outParams, - List/*!*/ localVariables, - [Captured] StmtList/*!*/ structuredStmts, - QKeyValue kv, - Errors/*!*/ errorHandler) - : base(tok, name, typeParams, inParams, outParams) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(typeParams != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(localVariables != null); - Contract.Requires(structuredStmts != null); - Contract.Requires(errorHandler != null); - LocVars = localVariables; - StructuredStmts = structuredStmts; - BigBlocksResolutionContext ctx = new BigBlocksResolutionContext(structuredStmts, errorHandler); - Blocks = ctx.Blocks; - BlockPredecessorsComputed = false; - scc = null; - Attributes = kv; - } - - public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] List block) - : this(tok, name, typeParams, inParams, outParams, localVariables, block, null) { - Contract.Requires(cce.NonNullElements(block)); - Contract.Requires(localVariables != null); - Contract.Requires(outParams != null); - Contract.Requires(inParams != null); - Contract.Requires(typeParams != null); - Contract.Requires(name != null); - Contract.Requires(tok != null); - //:this(tok, name, typeParams, inParams, outParams, localVariables, block, null); - } - - public Implementation(IToken/*!*/ tok, - string/*!*/ name, - List/*!*/ typeParams, - List/*!*/ inParams, - List/*!*/ outParams, - List/*!*/ localVariables, - [Captured] List/*!*/ blocks, - QKeyValue kv) - : base(tok, name, typeParams, inParams, outParams) { - Contract.Requires(name != null); - Contract.Requires(inParams != null); - Contract.Requires(outParams != null); - Contract.Requires(localVariables != null); - Contract.Requires(cce.NonNullElements(blocks)); - LocVars = localVariables; - Blocks = blocks; - BlockPredecessorsComputed = false; - scc = null; - Attributes = kv; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "implementation "); - EmitAttributes(stream); - stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - EmitSignature(stream, false); - stream.WriteLine(); - - stream.WriteLine(level, "{0}", '{'); - - foreach (Variable/*!*/ v in this.LocVars) { - Contract.Assert(v != null); - v.Emit(stream, level + 1); - } - - if (this.StructuredStmts != null && !CommandLineOptions.Clo.PrintInstrumented && !CommandLineOptions.Clo.PrintInlined) { - if (this.LocVars.Count > 0) { - stream.WriteLine(); - } - if (CommandLineOptions.Clo.PrintUnstructured < 2) { - if (CommandLineOptions.Clo.PrintUnstructured == 1) { - stream.WriteLine(this, level + 1, "/*** structured program:"); - } - this.StructuredStmts.Emit(stream, level + 1); - if (CommandLineOptions.Clo.PrintUnstructured == 1) { - stream.WriteLine(level + 1, "**** end structured program */"); - } - } - } - - if (this.StructuredStmts == null || 1 <= CommandLineOptions.Clo.PrintUnstructured || - CommandLineOptions.Clo.PrintInstrumented || CommandLineOptions.Clo.PrintInlined) { - foreach (Block b in this.Blocks) { - b.Emit(stream, level + 1); - } - } - - stream.WriteLine(level, "{0}", '}'); - - stream.WriteLine(); - stream.WriteLine(); - } - public override void Register(ResolutionContext rc) { - //Contract.Requires(rc != null); - // nothing to register - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (Proc != null) { - // already resolved - return; - } - - DeclWithFormals dwf = rc.LookUpProcedure(cce.NonNull(this.Name)); - Proc = dwf as Procedure; - if (dwf == null) { - rc.Error(this, "implementation given for undeclared procedure: {0}", this.Name); - } else if (Proc == null) { - rc.Error(this, "implementations given for function, not procedure: {0}", this.Name); - } - - int previousTypeBinderState = rc.TypeBinderState; - try { - RegisterTypeParameters(rc); - - rc.PushVarContext(); - RegisterFormals(InParams, rc); - RegisterFormals(OutParams, rc); - - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Register(rc); - v.Resolve(rc); - } - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.ResolveWhere(rc); - } - - rc.PushProcedureContext(); - foreach (Block b in Blocks) { - b.Register(rc); - } - - ResolveAttributes(rc); - - rc.StateMode = ResolutionContext.State.Two; - foreach (Block b in Blocks) { - b.Resolve(rc); - } - rc.StateMode = ResolutionContext.State.Single; - - rc.PopProcedureContext(); - rc.PopVarContext(); - - Type.CheckBoundVariableOccurrences(TypeParameters, - new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - this.tok, "implementation arguments", - rc); - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - SortTypeParams(); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - base.Typecheck(tc); - - Contract.Assume(this.Proc != null); - - if (this.TypeParameters.Count != Proc.TypeParameters.Count) { - tc.Error(this, "mismatched number of type parameters in procedure implementation: {0}", - this.Name); - } else { - // if the numbers of type parameters are different, it is - // difficult to compare the argument types - MatchFormals(this.InParams, Proc.InParams, "in", tc); - MatchFormals(this.OutParams, Proc.OutParams, "out", tc); - } - - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Typecheck(tc); - } - List oldFrame = tc.Frame; - bool oldYields = tc.Yields; - tc.Frame = Proc.Modifies; - tc.Yields = QKeyValue.FindBoolAttribute(Proc.Attributes, "yields"); - foreach (Block b in Blocks) { - b.Typecheck(tc); - } - Contract.Assert(tc.Frame == Proc.Modifies); - tc.Frame = oldFrame; - tc.Yields = oldYields; - } - void MatchFormals(List/*!*/ implFormals, List/*!*/ procFormals, string/*!*/ inout, TypecheckingContext/*!*/ tc) { - Contract.Requires(implFormals != null); - Contract.Requires(procFormals != null); - Contract.Requires(inout != null); - Contract.Requires(tc != null); - if (implFormals.Count != procFormals.Count) { - tc.Error(this, "mismatched number of {0}-parameters in procedure implementation: {1}", - inout, this.Name); - } else { - // unify the type parameters so that types can be compared - Contract.Assert(Proc != null); - Contract.Assert(this.TypeParameters.Count == Proc.TypeParameters.Count); - - IDictionary/*!*/ subst1 = - new Dictionary(); - IDictionary/*!*/ subst2 = - new Dictionary(); - - for (int i = 0; i < this.TypeParameters.Count; ++i) { - TypeVariable/*!*/ newVar = - new TypeVariable(Token.NoToken, Proc.TypeParameters[i].Name); - Contract.Assert(newVar != null); - subst1.Add(Proc.TypeParameters[i], newVar); - subst2.Add(this.TypeParameters[i], newVar); - } - - for (int i = 0; i < implFormals.Count; i++) { - // the names of the formals are allowed to change from the proc to the impl - - // but types must be identical - Type t = cce.NonNull((Variable)implFormals[i]).TypedIdent.Type.Substitute(subst2); - Type u = cce.NonNull((Variable)procFormals[i]).TypedIdent.Type.Substitute(subst1); - if (!t.Equals(u)) { - string/*!*/ a = cce.NonNull((Variable)implFormals[i]).Name; - Contract.Assert(a != null); - string/*!*/ b = cce.NonNull((Variable)procFormals[i]).Name; - Contract.Assert(b != null); - string/*!*/ c; - if (a == b) { - c = a; - } else { - c = String.Format("{0} (named {1} in implementation)", b, a); - } - tc.Error(this, "mismatched type of {0}-parameter in implementation {1}: {2}", inout, this.Name, c); - } - } - } - } - - private Dictionary/*?*/ formalMap = null; - public void ResetImplFormalMap() { - this.formalMap = null; - } - public Dictionary/*!*/ GetImplFormalMap() { - Contract.Ensures(Contract.Result>() != null); - - if (this.formalMap != null) - return this.formalMap; - else { - Dictionary/*!*/ map = new Dictionary (InParams.Count + OutParams.Count); - - Contract.Assume(this.Proc != null); - Contract.Assume(InParams.Count == Proc.InParams.Count); - for (int i = 0; i < InParams.Count; i++) { - Variable/*!*/ v = InParams[i]; - Contract.Assert(v != null); - IdentifierExpr ie = new IdentifierExpr(v.tok, v); - Variable/*!*/ pv = Proc.InParams[i]; - Contract.Assert(pv != null); - map.Add(pv, ie); - } - System.Diagnostics.Debug.Assert(OutParams.Count == Proc.OutParams.Count); - for (int i = 0; i < OutParams.Count; i++) { - Variable/*!*/ v = cce.NonNull(OutParams[i]); - IdentifierExpr ie = new IdentifierExpr(v.tok, v); - Variable pv = cce.NonNull(Proc.OutParams[i]); - map.Add(pv, ie); - } - this.formalMap = map; - - if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { - Console.WriteLine("Implementation.GetImplFormalMap on {0}:", this.Name); - using (TokenTextWriter stream = new TokenTextWriter("", Console.Out, /*setTokens=*/false, /*pretty=*/ false)) { - foreach (var e in map) { - Console.Write(" "); - cce.NonNull((Variable/*!*/)e.Key).Emit(stream, 0); - Console.Write(" --> "); - cce.NonNull((Expr)e.Value).Emit(stream); - Console.WriteLine(); - } - } - } - - return map; - } - } - - /// - /// Return a collection of blocks that are reachable from the block passed as a parameter. - /// The block must be defined in the current implementation - /// - public ICollection GetConnectedComponents(Block startingBlock) { - Contract.Requires(startingBlock != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); - Contract.Assert(this.Blocks.Contains(startingBlock)); - - if (!this.BlockPredecessorsComputed) - ComputeStronglyConnectedComponents(); - -#if DEBUG_PRINT - System.Console.WriteLine("* Strongly connected components * \n{0} \n ** ", scc); -#endif - - foreach (ICollection component in cce.NonNull(this.scc)) { - foreach (Block/*!*/ b in component) { - Contract.Assert(b != null); - if (b == startingBlock) // We found the compontent that owns the startingblock - { - return component; - } - } - } - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // if we are here, it means that the block is not in one of the components. This is an error. - } - - /// - /// Compute the strongly connected compontents of the blocks in the implementation. - /// As a side effect, it also computes the "predecessor" relation for the block in the implementation - /// - override public void ComputeStronglyConnectedComponents() { - if (!this.BlockPredecessorsComputed) - ComputePredecessorsForBlocks(); - - Adjacency next = new Adjacency(Successors); - Adjacency prev = new Adjacency(Predecessors); - - this.scc = new StronglyConnectedComponents(this.Blocks, next, prev); - scc.Compute(); - - - foreach (Block/*!*/ block in this.Blocks) { - Contract.Assert(block != null); - block.Predecessors = new List(); - } - - } - - /// - /// Reset the abstract stated computed before - /// - override public void ResetAbstractInterpretationState() { - foreach (Block/*!*/ b in this.Blocks) { - Contract.Assert(b != null); - b.ResetAbstractInterpretationState(); - } - } - - /// - /// A private method used as delegate for the strongly connected components. - /// It return, given a node, the set of its successors - /// - private IEnumerable/**//*!*/ Successors(Block node) { - Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - - GotoCmd gotoCmd = node.TransferCmd as GotoCmd; - - if (gotoCmd != null) { // If it is a gotoCmd - Contract.Assert(gotoCmd.labelTargets != null); - - return gotoCmd.labelTargets; - } else { // otherwise must be a ReturnCmd - Contract.Assert(node.TransferCmd is ReturnCmd); - - return new List(); - } - } - - /// - /// A private method used as delegate for the strongly connected components. - /// It return, given a node, the set of its predecessors - /// - private IEnumerable/**//*!*/ Predecessors(Block node) { - Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - - Contract.Assert(this.BlockPredecessorsComputed); - - return node.Predecessors; - } - - /// - /// Compute the predecessor informations for the blocks - /// - public void ComputePredecessorsForBlocks() { - foreach (Block b in this.Blocks) { - b.Predecessors = new List(); - } - foreach (Block b in this.Blocks) { - GotoCmd gtc = b.TransferCmd as GotoCmd; - if (gtc != null) { - Contract.Assert(gtc.labelTargets != null); - foreach (Block/*!*/ dest in gtc.labelTargets) { - Contract.Assert(dest != null); - dest.Predecessors.Add(b); - } - } - } - this.BlockPredecessorsComputed = true; - } - - public void PruneUnreachableBlocks() { - ArrayList /*Block!*/ visitNext = new ArrayList /*Block!*/ (); - List reachableBlocks = new List(); - HashSet reachable = new HashSet(); // the set of elements in "reachableBlocks" - - visitNext.Add(this.Blocks[0]); - while (visitNext.Count != 0) { - Block b = cce.NonNull((Block)visitNext[visitNext.Count - 1]); - visitNext.RemoveAt(visitNext.Count - 1); - if (!reachable.Contains(b)) { - reachableBlocks.Add(b); - reachable.Add(b); - if (b.TransferCmd is GotoCmd) { - if (CommandLineOptions.Clo.PruneInfeasibleEdges) { - foreach (Cmd/*!*/ s in b.Cmds) { - Contract.Assert(s != null); - if (s is PredicateCmd) { - LiteralExpr e = ((PredicateCmd)s).Expr as LiteralExpr; - if (e != null && e.IsFalse) { - // This statement sequence will never reach the end, because of this "assume false" or "assert false". - // Hence, it does not reach its successors. - b.TransferCmd = new ReturnCmd(b.TransferCmd.tok); - goto NEXT_BLOCK; - } - } - } - } - // it seems that the goto statement at the end may be reached - foreach (Block succ in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) { - Contract.Assume(succ != null); - visitNext.Add(succ); - } - } - } - NEXT_BLOCK: { - } - } - - this.Blocks = reachableBlocks; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitImplementation(this); - } - - public void FreshenCaptureStates() { - - // Assume commands with the "captureState" attribute allow model states to be - // captured for error reporting. - // Some program transformations, such as loop unrolling, duplicate parts of the - // program, leading to "capture-state-assumes" being duplicated. This leads - // to ambiguity when getting a state from the model. - // This method replaces the key of every "captureState" attribute with something - // unique - - int FreshCounter = 0; - foreach(var b in Blocks) { - List newCmds = new List(); - for (int i = 0; i < b.Cmds.Count(); i++) { - var a = b.Cmds[i] as AssumeCmd; - if (a != null && (QKeyValue.FindStringAttribute(a.Attributes, "captureState") != null)) { - string StateName = QKeyValue.FindStringAttribute(a.Attributes, "captureState"); - newCmds.Add(new AssumeCmd(Token.NoToken, a.Expr, FreshenCaptureState(a.Attributes, FreshCounter))); - FreshCounter++; - } - else { - newCmds.Add(b.Cmds[i]); - } - } - b.Cmds = newCmds; - } - } - - private QKeyValue FreshenCaptureState(QKeyValue Attributes, int FreshCounter) { - // Returns attributes identical to Attributes, but: - // - reversed (for ease of implementation; should not matter) - // - with the value for "captureState" replaced by a fresh value - Contract.Requires(QKeyValue.FindStringAttribute(Attributes, "captureState") != null); - string FreshValue = QKeyValue.FindStringAttribute(Attributes, "captureState") + "$renamed$" + Name + "$" + FreshCounter; - - QKeyValue result = null; - while (Attributes != null) { - if (Attributes.Key.Equals("captureState")) { - result = new QKeyValue(Token.NoToken, Attributes.Key, new List() { FreshValue }, result); - } else { - result = new QKeyValue(Token.NoToken, Attributes.Key, Attributes.Params, result); - } - Attributes = Attributes.Next; - } - return result; - } - - } - - - public class TypedIdent : Absy { - public const string NoName = ""; - - private string/*!*/ _name; - - public string/*!*/ Name { - get { - Contract.Ensures(Contract.Result() != null); - return this._name; - } - set { - Contract.Requires(value != null); - this._name = value; - } - } - - private Type/*!*/ _type; - - public Type/*!*/ Type { - get { - Contract.Ensures(Contract.Result() != null); - return this._type; - } - set { - Contract.Requires(value != null); - this._type = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._name != null); - Contract.Invariant(this._type != null); - } - - public Expr WhereExpr; - // [NotDelayed] - public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type) - : this(tok, name, type, null) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(type != null); - Contract.Ensures(this.WhereExpr == null); //PM: needed to verify BoogiePropFactory.FreshBoundVariable - //:this(tok, name, type, null); // here for aesthetic reasons - } - // [NotDelayed] - public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, Expr whereExpr) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(type != null); - Contract.Ensures(this.WhereExpr == whereExpr); - this._name = name; - this._type = type; - this.WhereExpr = whereExpr; - } - public bool HasName { - get { - return this.Name != NoName; - } - } - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.SetToken(this); - stream.push(); - if (this.Name != NoName) { - stream.Write("{0}: ", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - this.Type.Emit(stream); - if (this.WhereExpr != null) { - stream.sep(); - stream.Write(" where "); - this.WhereExpr.Emit(stream); - } - stream.pop(); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - // NOTE: WhereExpr needs to be resolved by the caller, because the caller must provide a modified ResolutionContext - this.Type = this.Type.ResolveType(rc); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - // type variables can occur when working with polymorphic functions/procedures - // if (!this.Type.IsClosed) - // tc.Error(this, "free variables in type of an identifier: {0}", - // this.Type.FreeVariables); - if (this.WhereExpr != null) { - this.WhereExpr.Typecheck(tc); - Contract.Assert(this.WhereExpr.Type != null); // follows from postcondition of Expr.Typecheck - if (!this.WhereExpr.Type.Unify(Type.Bool)) { - tc.Error(this, "where clauses must be of type bool"); - } - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypedIdent(this); - } - } - - #region Helper methods for generic Sequences - - public static class TypeVariableSeqAlgorithms { - public static void AppendWithoutDups(this List tvs, List s1) { - Contract.Requires(s1 != null); - for (int i = 0; i < s1.Count; i++) { - TypeVariable/*!*/ next = s1[i]; - Contract.Assert(next != null); - if (!tvs.Contains(next)) - tvs.Add(next); - } - } - } - - public static class Emitter { - - public static void Emit(this List/*!*/ decls, TokenTextWriter stream) { - Contract.Requires(stream != null); - Contract.Requires(cce.NonNullElements(decls)); - bool first = true; - foreach (Declaration d in decls) { - if (d == null) - continue; - if (first) { - first = false; - } else { - stream.WriteLine(); - } - d.Emit(stream, 0); - } - } - - public static void Emit(this List ss, TokenTextWriter stream) { - Contract.Requires(stream != null); - string sep = ""; - foreach (string/*!*/ s in ss) { - Contract.Assert(s != null); - stream.Write(sep); - sep = ", "; - stream.Write(s); - } - } - - public static void Emit(this IList ts, TokenTextWriter stream) { - Contract.Requires(stream != null); - string sep = ""; - stream.push(); - foreach (Expr/*!*/ e in ts) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - stream.sep(); - e.Emit(stream); - } - stream.pop(); - } - - public static void Emit(this List ids, TokenTextWriter stream, bool printWhereComments) { - Contract.Requires(stream != null); - string sep = ""; - foreach (IdentifierExpr/*!*/ e in ids) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - - if (printWhereComments && e.Decl != null && e.Decl.TypedIdent.WhereExpr != null) { - stream.Write(" /* where "); - e.Decl.TypedIdent.WhereExpr.Emit(stream); - stream.Write(" */"); - } - } - } - - public static void Emit(this List vs, TokenTextWriter stream, bool emitAttributes) { - Contract.Requires(stream != null); - string sep = ""; - stream.push(); - foreach (Variable/*!*/ v in vs) { - Contract.Assert(v != null); - stream.Write(sep); - sep = ", "; - stream.sep(); - v.EmitVitals(stream, 0, emitAttributes); - } - stream.pop(); - } - - public static void Emit(this List tys, TokenTextWriter stream, string separator) { - Contract.Requires(separator != null); - Contract.Requires(stream != null); - string sep = ""; - foreach (Type/*!*/ v in tys) { - Contract.Assert(v != null); - stream.Write(sep); - sep = separator; - v.Emit(stream); - } - } - - public static void Emit(this List tvs, TokenTextWriter stream, string separator) { - Contract.Requires(separator != null); - Contract.Requires(stream != null); - string sep = ""; - foreach (TypeVariable/*!*/ v in tvs) { - Contract.Assert(v != null); - stream.Write(sep); - sep = separator; - v.Emit(stream); - } - } - - } - #endregion - - - #region Regular Expressions - // a data structure to recover the "program structure" from the flow graph - public abstract class RE : Cmd { - public RE() - : base(Token.NoToken) { - } - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - throw new NotImplementedException(); - } - } - public class AtomicRE : RE { - private Block/*!*/ _b; - - public Block b - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._b; - } - set - { - Contract.Requires(value != null); - this._b = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._b != null); - } - - public AtomicRE(Block block) { - Contract.Requires(block != null); - this._b = block; - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - b.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - b.Typecheck(tc); - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - b.Emit(stream, level); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAtomicRE(this); - } - } - public abstract class CompoundRE : RE { - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - return; - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - return; - } - } - public class Sequential : CompoundRE { - private RE/*!*/ _first; - - public RE/*!*/ first { - get { - Contract.Ensures(Contract.Result() != null); - return this._first; - } - set { - Contract.Requires(value != null); - this._first = value; - } - } - - private RE/*!*/ _second; - - public RE/*!*/ second { - get { - Contract.Ensures(Contract.Result() != null); - return this._second; - } - set { - Contract.Requires(value != null); - this._second = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._first != null); - Contract.Invariant(this._second != null); - } - - public Sequential(RE first, RE second) { - Contract.Requires(first != null); - Contract.Requires(second != null); - this._first = first; - this._second = second; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(); - stream.WriteLine("{0};", Indent(stream.UseForComputingChecksums ? 0 : level)); - first.Emit(stream, level + 1); - second.Emit(stream, level + 1); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitSequential(this); - } - } - public class Choice : CompoundRE { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._rs != null); - } - - private List/*!*/ _rs; - - public List/*!*/ rs { //Rename this (and _rs) if possible - get { - Contract.Ensures(Contract.Result>() != null); - return this._rs; - } - set { - Contract.Requires(value != null); - this._rs = value; - } - } - - public Choice(List operands) { - Contract.Requires(operands != null); - this._rs = operands; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(); - stream.WriteLine("{0}[]", Indent(stream.UseForComputingChecksums ? 0 : level)); - foreach (RE/*!*/ r in rs) { - Contract.Assert(r != null); - r.Emit(stream, level + 1); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitChoice(this); - } - } - public class DAG2RE { - public static RE Transform(Block b) { - Contract.Requires(b != null); - Contract.Ensures(Contract.Result() != null); - TransferCmd tc = b.TransferCmd; - if (tc is ReturnCmd) { - return new AtomicRE(b); - } else if (tc is GotoCmd) { - GotoCmd/*!*/ g = (GotoCmd)tc; - Contract.Assert(g != null); - Contract.Assume(g.labelTargets != null); - if (g.labelTargets.Count == 1) { - return new Sequential(new AtomicRE(b), Transform(cce.NonNull(g.labelTargets[0]))); - } else { - List rs = new List(); - foreach (Block/*!*/ target in g.labelTargets) { - Contract.Assert(target != null); - RE r = Transform(target); - rs.Add(r); - } - RE second = new Choice(rs); - return new Sequential(new AtomicRE(b), second); - } - } else { - Contract.Assume(false); - throw new cce.UnreachableException(); - } - } - } - - #endregion - - // NOTE: This class is here for convenience, since this file's - // classes are used pretty much everywhere. - - public class BoogieDebug { - public static bool DoPrinting = false; - - public static void Write(string format, params object[] args) { - Contract.Requires(args != null); - Contract.Requires(format != null); - if (DoPrinting) { - Console.Error.Write(format, args); - } - } - - public static void WriteLine(string format, params object[] args) { - Contract.Requires(args != null); - Contract.Requires(format != null); - if (DoPrinting) { - Console.Error.WriteLine(format, args); - } - } - - public static void WriteLine() { - if (DoPrinting) { - Console.Error.WriteLine(); - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- +namespace Microsoft.Boogie.AbstractInterpretation { + using System.Diagnostics; + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + public class CallSite { + public readonly Implementation/*!*/ Impl; + public readonly Block/*!*/ Block; + public readonly int Statement; // invariant: Block[Statement] is CallCmd + public readonly ProcedureSummaryEntry/*!*/ SummaryEntry; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Impl != null); + Contract.Invariant(Block != null); + Contract.Invariant(SummaryEntry != null); + } + + + public CallSite(Implementation impl, Block b, int stmt, ProcedureSummaryEntry summaryEntry) { + Contract.Requires(summaryEntry != null); + Contract.Requires(b != null); + Contract.Requires(impl != null); + this.Impl = impl; + this.Block = b; + this.Statement = stmt; + this.SummaryEntry = summaryEntry; + } + } + + public class ProcedureSummaryEntry { + + private HashSet/*!*/ _returnPoints; // whenever OnExit changes, we start analysis again at all the ReturnPoints + + public HashSet/*!*/ ReturnPoints { + get { + Contract.Ensures(Contract.Result>() != null); + return this._returnPoints; + } + set { + Contract.Requires(value != null); + this._returnPoints = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._returnPoints != null); + } + + public ProcedureSummaryEntry() { + this._returnPoints = new HashSet(); + } + + } // class + + public class ProcedureSummary : ArrayList/**/ + { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant( + !IsReadOnly && !IsFixedSize); + } + + public new ProcedureSummaryEntry/*!*/ this[int i] { + get { + Contract.Requires(0 <= i && i < Count); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull((ProcedureSummaryEntry/*!*/)base[i]); + } + } + + } // class +} // namespace + +namespace Microsoft.Boogie { + using System; + using System.Linq; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Diagnostics.Contracts; + using Microsoft.Boogie.AbstractInterpretation; + using Microsoft.Boogie.GraphUtil; + using Set = GSet; + + [ContractClass(typeof(AbsyContracts))] + public abstract class Absy { + private IToken/*!*/ _tok; + private int uniqueId; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._tok != null); + } + + public IToken tok { //Rename this property and "_tok" if possible + get { + Contract.Ensures(Contract.Result() != null); + return this._tok; + } + set { + Contract.Requires(value != null); + this._tok = value; + } + } + + public int Line { + get { + return tok != null ? tok.line : -1; + } + } + public int Col { + get { + return tok != null ? tok.col : -1; + } + } + + public Absy(IToken tok) { + Contract.Requires(tok != null); + this._tok = tok; + this.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); + } + + private static int CurrentAbsyNodeId = -1; + + // We uniquely number every AST node to make them + // suitable for our implementation of functional maps. + // + public int UniqueId { + get { + return this.uniqueId; + } + } + + private const int indent_size = 2; + protected static string Indent(int level) { + return new string(' ', (indent_size * level)); + } + [NeedsContracts] + public abstract void Resolve(ResolutionContext/*!*/ rc); + + /// + /// Requires the object to have been successfully resolved. + /// + /// + [NeedsContracts] + public abstract void Typecheck(TypecheckingContext/*!*/ tc); + /// + /// Intorduced this so the uniqueId is not the same on a cloned object. + /// + /// + public virtual Absy Clone() { + Contract.Ensures(Contract.Result() != null); + Absy/*!*/ result = cce.NonNull((Absy/*!*/)this.MemberwiseClone()); + result.uniqueId = System.Threading.Interlocked.Increment(ref CurrentAbsyNodeId); // BUGBUG?? + + if (InternalNumberedMetadata != null) { + // This should probably use the lock + result.InternalNumberedMetadata = new List(this.InternalNumberedMetadata); + } + + return result; + } + + public virtual Absy StdDispatch(StandardVisitor visitor) { + Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + System.Diagnostics.Debug.Fail("Unknown Absy node type: " + this.GetType()); + throw new System.NotImplementedException(); + } + + #region numberedmetadata + // Implementation of Numbered Metadata + // This allows any number of arbitrary objects to be + // associated with an instance of an Absy at run time + // in a type safe manner using an integer as a key. + + // We could use a dictionary but we use a List for look up speed + // For this to work well the user needs to use small integers as + // keys. The list is created lazily to minimise memory overhead. + private volatile List InternalNumberedMetadata = null; + + // The lock exists to ensure that InternalNumberedMetadata is a singleton + // for every instance of this class. + // It is static to minimise the memory overhead (we don't want a lock per instance). + private static readonly Object NumberedMetadataLock = new object(); + + /// + /// Gets the number of meta data objects associated with this instance + /// + /// The numbered meta data count. + public int NumberedMetaDataCount + { + get { return InternalNumberedMetadata == null? 0: InternalNumberedMetadata.Count; } + } + + /// + /// Gets an IEnumerable over the numbered metadata associated + /// with this instance. + /// + /// + /// The numbered meta data enumerable that looks like the Enumerable + /// of a dictionary. + /// + public IEnumerable> NumberedMetadata + { + get { + if (InternalNumberedMetadata == null) + return Enumerable.Empty>(); + else + return InternalNumberedMetadata.Select((v, index) => new KeyValuePair(index, v)); + } + } + + /// + /// Gets the metatdata at specified index. + /// ArgumentOutOfRange exception is raised if it is not available. + /// InvalidCastExcpetion is raised if the metadata is available but the wrong type was requested. + /// + /// The stored metadata of type T + /// The index of the metadata + /// The type of the metadata object required + public T GetMetadata(int index) { + // We aren't using NumberedMetadataLock for speed. Perhaps we should be using it? + if (InternalNumberedMetadata == null) + throw new ArgumentOutOfRangeException(); + + if (InternalNumberedMetadata[index] is T) + return (T) InternalNumberedMetadata[index]; + else if (InternalNumberedMetadata[index] == null) { + throw new InvalidCastException("Numbered metadata " + index + + " is null which cannot be casted to " + typeof(T)); + } + else { + throw new InvalidCastException("Numbered metadata " + index + + " is of type " + InternalNumberedMetadata[index].GetType() + + " rather than requested type " + typeof(T)); + } + } + + private void InitialiseNumberedMetadata() { + // Ensure InternalNumberedMetadata is a singleton + if (InternalNumberedMetadata == null) { + lock (NumberedMetadataLock) { + if (InternalNumberedMetadata == null) + InternalNumberedMetadata = new List(); + } + } + } + + /// + /// Sets the metadata for this instace at a specified index. + /// + /// The index of the metadata + /// The value to set + /// The type of value + public void SetMetadata(int index, T value) { + InitialiseNumberedMetadata(); + + if (index < 0) + throw new IndexOutOfRangeException(); + + lock (NumberedMetadataLock) { + if (index < InternalNumberedMetadata.Count) + InternalNumberedMetadata[index] = value; + else { + // Make sure expansion only happens once whilst we pad + if (InternalNumberedMetadata.Capacity <= index) { + // Use the next available power of 2 + InternalNumberedMetadata.Capacity = (int) Math.Pow(2, Math.Ceiling(Math.Log(index+1,2))); + } + + // Pad with nulls + while (InternalNumberedMetadata.Count < index) + InternalNumberedMetadata.Add (null); + + InternalNumberedMetadata.Add(value); + Debug.Assert(InternalNumberedMetadata.Count == (index + 1)); + } + } + } + + #endregion + + } + + [ContractClassFor(typeof(Absy))] + public abstract class AbsyContracts : Absy { + public override void Resolve(ResolutionContext rc) { + Contract.Requires(rc != null); + throw new NotImplementedException(); + } + public AbsyContracts() :base(null){ + + } + public override void Typecheck(TypecheckingContext tc) { + Contract.Requires(tc != null); + throw new NotImplementedException(); + } + } + + public interface IPotentialErrorNode + { + TGet ErrorData + { + get; + } + } + + public interface IPotentialErrorNode : IPotentialErrorNode + { + new TSet ErrorData + { + set; + } + } + + public class Program : Absy { + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(this.topLevelDeclarations)); + Contract.Invariant(cce.NonNullElements(this.globalVariablesCache, true)); + } + + public Program() + : base(Token.NoToken) { + this.topLevelDeclarations = new List(); + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.SetToken(this); + this.topLevelDeclarations.Emit(stream); + } + + public void ProcessDatatypeConstructors() { + Dictionary constructors = new Dictionary(); + List prunedTopLevelDeclarations = new List(); + foreach (Declaration decl in TopLevelDeclarations) { + Function func = decl as Function; + if (func == null || !QKeyValue.FindBoolAttribute(decl.Attributes, "constructor")) { + prunedTopLevelDeclarations.Add(decl); + continue; + } + if (constructors.ContainsKey(func.Name)) continue; + DatatypeConstructor constructor = new DatatypeConstructor(func); + constructors.Add(func.Name, constructor); + prunedTopLevelDeclarations.Add(constructor); + } + ClearTopLevelDeclarations(); + AddTopLevelDeclarations(prunedTopLevelDeclarations); + + foreach (DatatypeConstructor f in constructors.Values) { + for (int i = 0; i < f.InParams.Count; i++) { + DatatypeSelector selector = new DatatypeSelector(f, i); + f.selectors.Add(selector); + AddTopLevelDeclaration(selector); + } + DatatypeMembership membership = new DatatypeMembership(f); + f.membership = membership; + AddTopLevelDeclaration(membership); + } + } + + /// + /// Returns the number of name resolution errors. + /// + /// + public int Resolve() { + return Resolve((IErrorSink)null); + } + + public int Resolve(IErrorSink errorSink) { + ResolutionContext rc = new ResolutionContext(errorSink); + Resolve(rc); + return rc.ErrorCount; + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Helpers.ExtraTraceInformation("Starting resolution"); + + foreach (var d in TopLevelDeclarations) { + d.Register(rc); + } + + ResolveTypes(rc); + + var prunedTopLevelDecls = new List(); + foreach (var d in TopLevelDeclarations) { + if (QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) { + continue; + } + // resolve all the non-type-declarations + if (!(d is TypeCtorDecl || d is TypeSynonymDecl)) { + int e = rc.ErrorCount; + d.Resolve(rc); + 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); + } + ClearTopLevelDeclarations(); + AddTopLevelDeclarations(prunedTopLevelDecls); + + foreach (var v in Variables) { + v.ResolveWhere(rc); + } + } + + private void ResolveTypes(ResolutionContext rc) { + Contract.Requires(rc != null); + // first resolve type constructors + foreach (var d in TopLevelDeclarations.OfType()) { + if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) + d.Resolve(rc); + } + + // collect type synonym declarations + List/*!*/ synonymDecls = new List(); + foreach (var d in TopLevelDeclarations.OfType()) { + Contract.Assert(d != null); + if (!QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) + synonymDecls.Add((TypeSynonymDecl)d); + } + + // then resolve the type synonyms by a simple + // fixed-point iteration + TypeSynonymDecl.ResolveTypeSynonyms(synonymDecls, rc); + } + + public int Typecheck() { + return this.Typecheck((IErrorSink)null); + } + + public int Typecheck(IErrorSink errorSink) { + TypecheckingContext tc = new TypecheckingContext(errorSink); + Typecheck(tc); + return tc.ErrorCount; + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Helpers.ExtraTraceInformation("Starting typechecking"); + + int oldErrorCount = tc.ErrorCount; + foreach (var d in TopLevelDeclarations) { + d.Typecheck(tc); + } + + if (oldErrorCount == tc.ErrorCount) { + // check whether any type proxies have remained uninstantiated + TypeAmbiguitySeeker/*!*/ seeker = new TypeAmbiguitySeeker(tc); + foreach (var d in TopLevelDeclarations) { + seeker.Visit(d); + } + } + } + + public override Absy Clone() + { + var cloned = (Program)base.Clone(); + cloned.topLevelDeclarations = new List(); + cloned.AddTopLevelDeclarations(topLevelDeclarations); + return cloned; + } + + [Rep] + private List/*!*/ topLevelDeclarations; + + public IEnumerable TopLevelDeclarations + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return topLevelDeclarations.AsReadOnly(); + } + + set + { + Contract.Requires(value != null); + // materialize the decls, in case there is any dependency + // back on topLevelDeclarations + var v = value.ToList(); + // remove null elements + v.RemoveAll(d => (d == null)); + // now clear the decls + ClearTopLevelDeclarations(); + // and add the values + AddTopLevelDeclarations(v); + } + } + + public void AddTopLevelDeclaration(Declaration decl) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + Contract.Requires(decl != null); + + topLevelDeclarations.Add(decl); + this.globalVariablesCache = null; + } + + public void AddTopLevelDeclarations(IEnumerable decls) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + Contract.Requires(cce.NonNullElements(decls)); + + topLevelDeclarations.AddRange(decls); + this.globalVariablesCache = null; + } + + public void RemoveTopLevelDeclaration(Declaration decl) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + + topLevelDeclarations.Remove(decl); + this.globalVariablesCache = null; + } + + public void RemoveTopLevelDeclarations(Predicate match) + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + + topLevelDeclarations.RemoveAll(match); + this.globalVariablesCache = null; + } + + public void ClearTopLevelDeclarations() + { + Contract.Requires(!TopLevelDeclarationsAreFrozen); + + topLevelDeclarations.Clear(); + this.globalVariablesCache = null; + } + + bool topLevelDeclarationsAreFrozen; + public bool TopLevelDeclarationsAreFrozen { get { return topLevelDeclarationsAreFrozen; } } + public void FreezeTopLevelDeclarations() + { + topLevelDeclarationsAreFrozen = true; + } + + Dictionary implementationsCache; + public IEnumerable Implementations + { + get + { + if (implementationsCache != null) + { + return implementationsCache.Values; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + implementationsCache = result.ToDictionary(p => p.Id); + } + return result; + } + } + + public Implementation FindImplementation(string id) + { + Implementation result = null; + if (implementationsCache != null && implementationsCache.TryGetValue(id, out result)) + { + return result; + } + else + { + return Implementations.FirstOrDefault(i => i.Id == id); + } + } + + List axiomsCache; + public IEnumerable Axioms + { + get + { + if (axiomsCache != null) + { + return axiomsCache; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + axiomsCache = result.ToList(); + } + return result; + } + } + + Dictionary proceduresCache; + public IEnumerable Procedures + { + get + { + if (proceduresCache != null) + { + return proceduresCache.Values; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + proceduresCache = result.ToDictionary(p => p.Name); + } + return result; + } + } + + public Procedure FindProcedure(string name) + { + Procedure result = null; + if (proceduresCache != null && proceduresCache.TryGetValue(name, out result)) + { + return result; + } + else + { + return Procedures.FirstOrDefault(p => p.Name == name); + } + } + + Dictionary functionsCache; + public IEnumerable Functions + { + get + { + if (functionsCache != null) + { + return functionsCache.Values; + } + var result = TopLevelDeclarations.OfType(); + if (topLevelDeclarationsAreFrozen) + { + functionsCache = result.ToDictionary(f => f.Name); + } + return result; + } + } + + public Function FindFunction(string name) + { + Function result = null; + if (functionsCache != null && functionsCache.TryGetValue(name, out result)) + { + return result; + } + else + { + return Functions.FirstOrDefault(f => f.Name == name); + } + } + + public IEnumerable Variables + { + get + { + return TopLevelDeclarations.OfType(); + } + } + + public IEnumerable Constants + { + get + { + return TopLevelDeclarations.OfType(); + } + } + + private IEnumerable globalVariablesCache = null; + public List/*!*/ GlobalVariables + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + + if (globalVariablesCache == null) + globalVariablesCache = TopLevelDeclarations.OfType(); + + return new List(globalVariablesCache); + } + } + + public IEnumerable Blocks() + { + return Implementations.Select(Item => Item.Blocks).SelectMany(Item => Item); + } + + public void ComputeStronglyConnectedComponents() { + foreach (var d in this.TopLevelDeclarations) { + d.ComputeStronglyConnectedComponents(); + } + } + + /// + /// Reset the abstract stated computed before + /// + public void ResetAbstractInterpretationState() { + foreach (var d in this.TopLevelDeclarations) { + d.ResetAbstractInterpretationState(); + } + } + + public void UnrollLoops(int n, bool uc) { + Contract.Requires(0 <= n); + foreach (var impl in Implementations) { + if (impl.Blocks != null && impl.Blocks.Count > 0) { + cce.BeginExpose(impl); + { + Block start = impl.Blocks[0]; + Contract.Assume(start != null); + Contract.Assume(cce.IsConsistent(start)); + impl.Blocks = LoopUnroll.UnrollLoops(start, n, uc); + impl.FreshenCaptureStates(); + } + cce.EndExpose(); + } + } + } + + void CreateProceduresForLoops(Implementation impl, Graph/*!*/ g, + List/*!*/ loopImpls, + Dictionary> fullMap) { + Contract.Requires(impl != null); + Contract.Requires(cce.NonNullElements(loopImpls)); + // Enumerate the headers + // for each header h: + // create implementation p_h with + // inputs = inputs, outputs, and locals of impl + // outputs = outputs and locals of impl + // locals = empty set + // add call o := p_h(i) at the beginning of the header block + // break the back edges whose target is h + // Enumerate the headers again to create the bodies of p_h + // for each header h: + // compute the loop corresponding to h + // make copies of all blocks in the loop for h + // delete all target edges that do not go to a block in the loop + // create a new entry block and a new return block + // add edges from entry block to the loop header and the return block + // add calls o := p_h(i) at the end of the blocks that are sources of back edges + foreach (Block block in impl.Blocks) + { + AddToFullMap(fullMap, impl.Name, block.Label, block); + } + + bool detLoopExtract = CommandLineOptions.Clo.DeterministicExtractLoops; + + Dictionary/*!*/>/*!*/ loopHeaderToInputs = new Dictionary/*!*/>(); + Dictionary/*!*/>/*!*/ loopHeaderToOutputs = new Dictionary/*!*/>(); + Dictionary/*!*/>/*!*/ loopHeaderToSubstMap = new Dictionary/*!*/>(); + Dictionary/*!*/ loopHeaderToLoopProc = new Dictionary(); + Dictionary/*!*/ loopHeaderToCallCmd1 = new Dictionary(); + Dictionary loopHeaderToCallCmd2 = new Dictionary(); + Dictionary loopHeaderToAssignCmd = new Dictionary(); + + foreach (Block/*!*/ header in g.Headers) { + Contract.Assert(header != null); + Contract.Assert(header != null); + List inputs = new List(); + List outputs = new List(); + List callInputs1 = new List(); + List callOutputs1 = new List(); + List callInputs2 = new List(); + List callOutputs2 = new List(); + List lhss = new List(); + List rhss = new List(); + Dictionary substMap = new Dictionary(); // Variable -> IdentifierExpr + + List/*!*/ targets = new List(); + HashSet footprint = new HashSet(); + + foreach (Block/*!*/ b in g.BackEdgeNodes(header)) + { + Contract.Assert(b != null); + foreach (Block/*!*/ block in g.NaturalLoops(header, b)) + { + Contract.Assert(block != null); + foreach (Cmd/*!*/ cmd in block.Cmds) + { + Contract.Assert(cmd != null); + cmd.AddAssignedVariables(targets); + + VariableCollector c = new VariableCollector(); + c.Visit(cmd); + footprint.UnionWith(c.usedVars); + } + } + } + + List/*!*/ globalMods = new List(); + Set targetSet = new Set(); + foreach (Variable/*!*/ v in targets) + { + Contract.Assert(v != null); + if (targetSet.Contains(v)) + continue; + targetSet.Add(v); + if (v is GlobalVariable) + globalMods.Add(new IdentifierExpr(Token.NoToken, v)); + } + + foreach (Variable v in impl.InParams) { + Contract.Assert(v != null); + if (!footprint.Contains(v)) continue; + callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); + inputs.Add(f); + callInputs2.Add(new IdentifierExpr(Token.NoToken, f)); + substMap[v] = new IdentifierExpr(Token.NoToken, f); + } + foreach (Variable v in impl.OutParams) { + Contract.Assert(v != null); + if (!footprint.Contains(v)) continue; + callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); + inputs.Add(f1); + if (targetSet.Contains(v)) + { + callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); + outputs.Add(f2); + callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); + rhss.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f2); + } + else + { + callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f1); + } + } + foreach (Variable v in impl.LocVars) { + Contract.Assert(v != null); + if (!footprint.Contains(v)) continue; + callInputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f1 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "in_" + v.Name, v.TypedIdent.Type), true); + inputs.Add(f1); + if (targetSet.Contains(v)) + { + callOutputs1.Add(new IdentifierExpr(Token.NoToken, v)); + Formal f2 = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "out_" + v.Name, v.TypedIdent.Type), false); + outputs.Add(f2); + callInputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + callOutputs2.Add(new IdentifierExpr(Token.NoToken, f2)); + lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, f2))); + rhss.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f2); + } + else + { + callInputs2.Add(new IdentifierExpr(Token.NoToken, f1)); + substMap[v] = new IdentifierExpr(Token.NoToken, f1); + } + } + + loopHeaderToInputs[header] = inputs; + loopHeaderToOutputs[header] = outputs; + loopHeaderToSubstMap[header] = substMap; + LoopProcedure loopProc = new LoopProcedure(impl, header, inputs, outputs, globalMods); + loopHeaderToLoopProc[header] = loopProc; + + CallCmd callCmd1 = new CallCmd(Token.NoToken, loopProc.Name, callInputs1, callOutputs1); + callCmd1.Proc = loopProc; + loopHeaderToCallCmd1[header] = callCmd1; + + CallCmd callCmd2 = new CallCmd(Token.NoToken, loopProc.Name, callInputs2, callOutputs2); + callCmd2.Proc = loopProc; + loopHeaderToCallCmd2[header] = callCmd2; + + Debug.Assert(lhss.Count == rhss.Count); + if (lhss.Count > 0) + { + AssignCmd assignCmd = new AssignCmd(Token.NoToken, lhss, rhss); + loopHeaderToAssignCmd[header] = assignCmd; + } + } + + // Keep track of the new blocks created: maps a header node to the + // header_last block that was created because of splitting header. + Dictionary newBlocksCreated = new Dictionary(); + + bool headRecursion = false; // testing an option to put recursive call before loop body + + IEnumerable sortedHeaders = g.SortHeadersByDominance(); + foreach (Block/*!*/ header in sortedHeaders) + { + Contract.Assert(header != null); + LoopProcedure loopProc = loopHeaderToLoopProc[header]; + Dictionary blockMap = new Dictionary(); + HashSet dummyBlocks = new HashSet(); + + CodeCopier codeCopier = new CodeCopier(loopHeaderToSubstMap[header]); // fix me + List inputs = loopHeaderToInputs[header]; + List outputs = loopHeaderToOutputs[header]; + int si_unique_loc = 1; // Added by AL: to distinguish the back edges + foreach (Block/*!*/ source in g.BackEdgeNodes(header)) { + Contract.Assert(source != null); + foreach (Block/*!*/ block in g.NaturalLoops(header, source)) { + Contract.Assert(block != null); + if (blockMap.ContainsKey(block)) + continue; + Block newBlock = new Block(); + newBlock.Label = block.Label; + if (headRecursion && block == header) + { + CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); + addUniqueCallAttr(si_unique_loc, callCmd); + si_unique_loc++; + newBlock.Cmds.Add(callCmd); // add the recursive call at head of loop + var rest = codeCopier.CopyCmdSeq(block.Cmds); + newBlock.Cmds.AddRange(rest); + } + else + newBlock.Cmds = codeCopier.CopyCmdSeq(block.Cmds); + blockMap[block] = newBlock; + if (newBlocksCreated.ContainsKey(block)) + { + Block newBlock2 = new Block(); + newBlock2.Label = newBlocksCreated[block].Label; + newBlock2.Cmds = codeCopier.CopyCmdSeq(newBlocksCreated[block].Cmds); + blockMap[newBlocksCreated[block]] = newBlock2; + } + //for detLoopExtract, need the immediate successors even outside the loop + if (detLoopExtract) { + GotoCmd auxGotoCmd = block.TransferCmd as GotoCmd; + Contract.Assert(auxGotoCmd != null && auxGotoCmd.labelNames != null && + auxGotoCmd.labelTargets != null && auxGotoCmd.labelTargets.Count >= 1); + foreach(var bl in auxGotoCmd.labelTargets) { + bool found = false; + foreach(var n in g.NaturalLoops(header, source)) { //very expensive, can we do a contains? + if (bl == n) { //clarify: is this the right comparison? + found = true; + break; + } + } + if (!found) { + Block auxNewBlock = new Block(); + auxNewBlock.Label = ((Block)bl).Label; + auxNewBlock.Cmds = codeCopier.CopyCmdSeq(((Block)bl).Cmds); + //add restoration code for such blocks + if (loopHeaderToAssignCmd.ContainsKey(header)) + { + AssignCmd assignCmd = loopHeaderToAssignCmd[header]; + auxNewBlock.Cmds.Add(assignCmd); + } + List lhsg = new List(); + List/*!*/ globalsMods = loopHeaderToLoopProc[header].Modifies; + foreach (IdentifierExpr gl in globalsMods) + lhsg.Add(new SimpleAssignLhs(Token.NoToken, gl)); + List rhsg = new List(); + foreach (IdentifierExpr gl in globalsMods) + rhsg.Add(new OldExpr(Token.NoToken, gl)); + if (lhsg.Count != 0) + { + AssignCmd globalAssignCmd = new AssignCmd(Token.NoToken, lhsg, rhsg); + auxNewBlock.Cmds.Add(globalAssignCmd); + } + blockMap[(Block)bl] = auxNewBlock; + } + } + + } + } + + List cmdSeq; + if (headRecursion) + cmdSeq = new List(); + else + { + CallCmd callCmd = (CallCmd)(loopHeaderToCallCmd2[header]).Clone(); + addUniqueCallAttr(si_unique_loc, callCmd); + si_unique_loc++; + cmdSeq = new List { callCmd }; + } + + Block/*!*/ block1 = new Block(Token.NoToken, source.Label + "_dummy", + new List{ new AssumeCmd(Token.NoToken, Expr.False) }, new ReturnCmd(Token.NoToken)); + Block/*!*/ block2 = new Block(Token.NoToken, block1.Label, + cmdSeq, new ReturnCmd(Token.NoToken)); + impl.Blocks.Add(block1); + dummyBlocks.Add(block1.Label); + + GotoCmd gotoCmd = source.TransferCmd as GotoCmd; + Contract.Assert(gotoCmd != null && gotoCmd.labelNames != null && gotoCmd.labelTargets != null && gotoCmd.labelTargets.Count >= 1); + List/*!*/ newLabels = new List(); + List/*!*/ newTargets = new List(); + for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { + if (gotoCmd.labelTargets[i] == header) + continue; + newTargets.Add(gotoCmd.labelTargets[i]); + newLabels.Add(gotoCmd.labelNames[i]); + } + newTargets.Add(block1); + newLabels.Add(block1.Label); + gotoCmd.labelNames = newLabels; + gotoCmd.labelTargets = newTargets; + blockMap[block1] = block2; + } + List/*!*/ blocks = new List(); + Block exit = new Block(Token.NoToken, "exit", new List(), new ReturnCmd(Token.NoToken)); + GotoCmd cmd = new GotoCmd(Token.NoToken, + new List { cce.NonNull(blockMap[header]).Label, exit.Label }, + new List { blockMap[header], exit }); + + if (detLoopExtract) //cutting the non-determinism + cmd = new GotoCmd(Token.NoToken, + new List { cce.NonNull(blockMap[header]).Label }, + new List { blockMap[header] }); + + Block entry; + List initCmds = new List(); + if (loopHeaderToAssignCmd.ContainsKey(header)) { + AssignCmd assignCmd = loopHeaderToAssignCmd[header]; + initCmds.Add(assignCmd); + } + + entry = new Block(Token.NoToken, "entry", initCmds, cmd); + blocks.Add(entry); + + foreach (Block/*!*/ block in blockMap.Keys) { + Contract.Assert(block != null); + Block/*!*/ newBlock = cce.NonNull(blockMap[block]); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + if (gotoCmd == null) { + newBlock.TransferCmd = new ReturnCmd(Token.NoToken); + } else { + Contract.Assume(gotoCmd.labelNames != null && gotoCmd.labelTargets != null); + List newLabels = new List(); + List newTargets = new List(); + for (int i = 0; i < gotoCmd.labelTargets.Count; i++) { + Block target = gotoCmd.labelTargets[i]; + if (blockMap.ContainsKey(target)) { + newLabels.Add(gotoCmd.labelNames[i]); + newTargets.Add(blockMap[target]); + } + } + if (newTargets.Count == 0) { + if (!detLoopExtract) + newBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + newBlock.TransferCmd = new ReturnCmd(Token.NoToken); + } else { + newBlock.TransferCmd = new GotoCmd(Token.NoToken, newLabels, newTargets); + } + } + blocks.Add(newBlock); + } + blocks.Add(exit); + Implementation loopImpl = + new Implementation(Token.NoToken, loopProc.Name, + new List(), inputs, outputs, new List(), blocks); + loopImpl.Proc = loopProc; + loopImpls.Add(loopImpl); + + // Make a (shallow) copy of the header before splitting it + Block origHeader = new Block(header.tok, header.Label, header.Cmds, header.TransferCmd); + + // Finally, add call to the loop in the containing procedure + string lastIterBlockName = header.Label + "_last"; + Block lastIterBlock = new Block(Token.NoToken, lastIterBlockName, header.Cmds, header.TransferCmd); + newBlocksCreated[header] = lastIterBlock; + header.Cmds = new List { loopHeaderToCallCmd1[header] }; + header.TransferCmd = new GotoCmd(Token.NoToken, new List { lastIterBlockName }, new List { lastIterBlock }); + impl.Blocks.Add(lastIterBlock); + blockMap[origHeader] = blockMap[header]; + blockMap.Remove(header); + + Contract.Assert(fullMap[impl.Name][header.Label] == header); + fullMap[impl.Name][header.Label] = origHeader; + + foreach (Block block in blockMap.Keys) + { + // Don't add dummy blocks to the map + if (dummyBlocks.Contains(blockMap[block].Label)) continue; + + // Following two statements are for nested loops: compose map + if (!fullMap[impl.Name].ContainsKey(block.Label)) continue; + var target = fullMap[impl.Name][block.Label]; + + AddToFullMap(fullMap, loopProc.Name, blockMap[block].Label, target); + } + + fullMap[impl.Name].Remove(header.Label); + fullMap[impl.Name][lastIterBlockName] = origHeader; + } + } + + private void addUniqueCallAttr(int val, CallCmd cmd) + { + var a = new List(); + a.Add(new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(val))); + + cmd.Attributes = new QKeyValue(Token.NoToken, "si_unique_call", a, cmd.Attributes); + } + + private void AddToFullMap(Dictionary> fullMap, string procName, string blockName, Block block) + { + if (!fullMap.ContainsKey(procName)) + fullMap[procName] = new Dictionary(); + fullMap[procName][blockName] = block; + } + + public static Graph BuildCallGraph(Program program) { + Graph callGraph = new Graph(); + Dictionary> procToImpls = new Dictionary>(); + foreach (var proc in program.Procedures) { + procToImpls[proc] = new HashSet(); + } + foreach (var impl in program.Implementations) { + if (impl.SkipVerification) continue; + callGraph.AddSource(impl); + procToImpls[impl.Proc].Add(impl); + } + foreach (var impl in program.Implementations) { + if (impl.SkipVerification) continue; + foreach (Block b in impl.Blocks) { + foreach (Cmd c in b.Cmds) { + CallCmd cc = c as CallCmd; + if (cc == null) continue; + foreach (Implementation callee in procToImpls[cc.Proc]) { + callGraph.AddEdge(impl, callee); + } + } + } + } + return callGraph; + } + + public static Graph/*!*/ GraphFromImpl(Implementation impl) { + Contract.Requires(impl != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>().Nodes)); + Contract.Ensures(Contract.Result>() != null); + + Graph g = new Graph(); + g.AddSource(impl.Blocks[0]); // there is always at least one node in the graph + + foreach (Block b in impl.Blocks) { + Contract.Assert(b != null); + GotoCmd gtc = b.TransferCmd as GotoCmd; + if (gtc != null) { + foreach (Block/*!*/ dest in cce.NonNull(gtc.labelTargets)) { + Contract.Assert(dest != null); + g.AddEdge(b, dest); + } + } + } + return g; + } + + public class IrreducibleLoopException : Exception {} + + public Graph ProcessLoops(Implementation impl) { + while (true) { + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + Graph/*!*/ g = GraphFromImpl(impl); + g.ComputeLoops(); + if (g.Reducible) { + return g; + } + throw new IrreducibleLoopException(); +#if USED_CODE + System.Diagnostics.Debug.Assert(g.SplitCandidates.Count > 0); + Block splitCandidate = null; + foreach (Block b in g.SplitCandidates) { + if (b.Predecessors.Length > 1) { + splitCandidate = b; + break; + } + } + System.Diagnostics.Debug.Assert(splitCandidate != null); + int count = 0; + foreach (Block b in splitCandidate.Predecessors) { + GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; + gotoCmd.labelNames.Remove(splitCandidate.Label); + gotoCmd.labelTargets.Remove(splitCandidate); + + CodeCopier codeCopier = new CodeCopier(new Hashtable(), new Hashtable()); + List newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds); + TransferCmd newTransferCmd; + GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd; + if (splitGotoCmd == null) { + newTransferCmd = new ReturnCmd(splitCandidate.tok); + } + else { + List newLabelNames = new List(); + newLabelNames.AddRange(splitGotoCmd.labelNames); + List newLabelTargets = new List(); + newLabelTargets.AddRange(splitGotoCmd.labelTargets); + newTransferCmd = new GotoCmd(splitCandidate.tok, newLabelNames, newLabelTargets); + } + Block copy = new Block(splitCandidate.tok, splitCandidate.Label + count++, newCmdSeq, newTransferCmd); + + impl.Blocks.Add(copy); + gotoCmd.AddTarget(copy); + } +#endif + } + } + + public Dictionary> ExtractLoops() + { + HashSet procsWithIrreducibleLoops = null; + return ExtractLoops(out procsWithIrreducibleLoops); + } + + public Dictionary> ExtractLoops(out HashSet procsWithIrreducibleLoops) + { + procsWithIrreducibleLoops = new HashSet(); + List/*!*/ loopImpls = new List(); + Dictionary> fullMap = new Dictionary>(); + foreach (var impl in this.Implementations) + { + if (impl.Blocks != null && impl.Blocks.Count > 0) + { + try + { + Graph g = ProcessLoops(impl); + CreateProceduresForLoops(impl, g, loopImpls, fullMap); + } + catch (IrreducibleLoopException) + { + System.Diagnostics.Debug.Assert(!fullMap.ContainsKey(impl.Name)); + fullMap[impl.Name] = null; + procsWithIrreducibleLoops.Add(impl.Name); + + if (CommandLineOptions.Clo.ExtractLoopsUnrollIrreducible) + { + // statically unroll loops in this procedure + + // First, build a map of the current blocks + var origBlocks = new Dictionary(); + foreach (var blk in impl.Blocks) origBlocks.Add(blk.Label, blk); + + // unroll + Block start = impl.Blocks[0]; + impl.Blocks = LoopUnroll.UnrollLoops(start, CommandLineOptions.Clo.RecursionBound, false); + + // Now construct the "map back" information + // Resulting block label -> original block + var blockMap = new Dictionary(); + foreach (var blk in impl.Blocks) + { + var sl = LoopUnroll.sanitizeLabel(blk.Label); + if (sl == blk.Label) blockMap.Add(blk.Label, blk); + else + { + Contract.Assert(origBlocks.ContainsKey(sl)); + blockMap.Add(blk.Label, origBlocks[sl]); + } + } + fullMap[impl.Name] = blockMap; + } + } + } + } + foreach (Implementation/*!*/ loopImpl in loopImpls) + { + Contract.Assert(loopImpl != null); + AddTopLevelDeclaration(loopImpl); + AddTopLevelDeclaration(loopImpl.Proc); + } + return fullMap; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitProgram(this); + } + + int extractedFunctionCount; + public string FreshExtractedFunctionName() + { + var c = System.Threading.Interlocked.Increment(ref extractedFunctionCount); + return string.Format("##extracted_function##{0}", c); + } + + private int invariantGenerationCounter = 0; + + public Constant MakeExistentialBoolean() { + Constant ExistentialBooleanConstant = new Constant(Token.NoToken, new TypedIdent(tok, "_b" + invariantGenerationCounter, Microsoft.Boogie.Type.Bool), false); + invariantGenerationCounter++; + ExistentialBooleanConstant.AddAttribute("existential", new object[] { Expr.True }); + AddTopLevelDeclaration(ExistentialBooleanConstant); + return ExistentialBooleanConstant; + } + + public PredicateCmd CreateCandidateInvariant(Expr e, string tag = null) { + Constant ExistentialBooleanConstant = MakeExistentialBoolean(); + IdentifierExpr ExistentialBoolean = new IdentifierExpr(Token.NoToken, ExistentialBooleanConstant); + PredicateCmd invariant = new AssertCmd(Token.NoToken, Expr.Imp(ExistentialBoolean, e)); + if (tag != null) + invariant.Attributes = new QKeyValue(Token.NoToken, "tag", new List(new object[] { tag }), null); + return invariant; + } + } + + //--------------------------------------------------------------------- + // Declarations + + [ContractClass(typeof(DeclarationContracts))] + public abstract class Declaration : Absy { + public QKeyValue Attributes; + + public Declaration(IToken tok) + : base(tok) { + Contract.Requires(tok != null); + } + + protected void EmitAttributes(TokenTextWriter stream) { + Contract.Requires(stream != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Emit(stream); + stream.Write(" "); + } + } + + protected void ResolveAttributes(ResolutionContext rc) { + Contract.Requires(rc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Resolve(rc); + } + } + + protected void TypecheckAttributes(TypecheckingContext rc) { + Contract.Requires(rc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Typecheck(rc); + } + } + + /// + /// If the declaration has an attribute {:name} or {:name true}, then set "result" to "true" and return "true". + /// If the declaration has an attribute {:name false}, then set "result" to "false" and return "true". + /// Otherwise, return "false" and leave "result" unchanged (which gives the caller an easy way to indicate + /// a default value if the attribute is not mentioned). + /// If there is more than one attribute called :name, then the last attribute rules. + /// + public bool CheckBooleanAttribute(string name, ref bool result) { + Contract.Requires(name != null); + var kv = FindAttribute(name); + if (kv != null) { + if (kv.Params.Count == 0) { + result = true; + return true; + } else if (kv.Params.Count == 1) { + var lit = kv.Params[0] as LiteralExpr; + if (lit != null && lit.isBool) { + result = lit.asBool; + return true; + } + } + } + return false; + } + + /// + /// Find and return the last occurrence of an attribute with the name "name", if any. If none, return null. + /// + public QKeyValue FindAttribute(string name) { + Contract.Requires(name != null); + QKeyValue res = null; + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + if (kv.Key == name) { + res = kv; + } + } + return res; + } + + // Look for {:name expr} in list of attributes. + public Expr FindExprAttribute(string name) { + Contract.Requires(name != null); + Expr res = null; + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + if (kv.Key == name) { + if (kv.Params.Count == 1 && kv.Params[0] is Expr) { + res = (Expr)kv.Params[0]; + } + } + } + return res; + } + + // Look for {:name string} in list of attributes. + public string FindStringAttribute(string name) { + Contract.Requires(name != null); + return QKeyValue.FindStringAttribute(this.Attributes, name); + } + + // Look for {:name N} or {:name N} in list of attributes. Return result in 'result' + // (which is not touched if there is no attribute specified). + // + // Returns false is there was an error processing the flag, true otherwise. + public bool CheckIntAttribute(string name, ref int result) { + Contract.Requires(name != null); + Expr expr = FindExprAttribute(name); + if (expr != null) { + if (expr is LiteralExpr && ((LiteralExpr)expr).isBigNum) { + result = ((LiteralExpr)expr).asBigNum.ToInt; + } else { + return false; + } + } + return true; + } + + public void AddAttribute(string name, params object[] vals) { + Contract.Requires(name != null); + QKeyValue kv; + for (kv = this.Attributes; kv != null; kv = kv.Next) { + if (kv.Key == name) { + kv.AddParams(vals); + break; + } + } + if (kv == null) { + Attributes = new QKeyValue(tok, name, new List(vals), Attributes); + } + } + + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + public abstract void Register(ResolutionContext/*!*/ rc); + + /// + /// Compute the strongly connected components of the declaration. + /// By default, it does nothing + /// + public virtual void ComputeStronglyConnectedComponents() { /* Does nothing */ + } + + /// + /// Reset the abstract stated computed before + /// + public virtual void ResetAbstractInterpretationState() { /* does nothing */ + } + } + [ContractClassFor(typeof(Declaration))] + public abstract class DeclarationContracts : Declaration { + public DeclarationContracts() :base(null){ + } + public override void Register(ResolutionContext rc) { + Contract.Requires(rc != null); + throw new NotImplementedException(); + } + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + } + + public class Axiom : Declaration { + private Expr/*!*/ expression; + + public Expr Expr { + get { + Contract.Ensures(Contract.Result() != null); + return this.expression; + } + set { + Contract.Requires(value != null); + this.expression = value; + } + } + + [ContractInvariantMethod] + void ExprInvariant() { + Contract.Invariant(this.expression != null); + } + + public string Comment; + + public Axiom(IToken tok, Expr expr) + : this(tok, expr, null) { + Contract.Requires(expr != null); + Contract.Requires(tok != null); + } + + public Axiom(IToken/*!*/ tok, Expr/*!*/ expr, string comment) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + this.expression = expr; + Comment = comment; + } + + public Axiom(IToken tok, Expr expr, string comment, QKeyValue kv) + : this(tok, expr, comment) { + Contract.Requires(expr != null); + Contract.Requires(tok != null); + this.Attributes = kv; + } + + public bool DependenciesCollected { get; set; } + + ISet functionDependencies; + + public ISet FunctionDependencies + { + get { return functionDependencies; } + } + + public void AddFunctionDependency(Function function) + { + Contract.Requires(function != null); + + if (functionDependencies == null) + { + functionDependencies = new HashSet(); + } + functionDependencies.Add(function); + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "axiom "); + EmitAttributes(stream); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddAxiom(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(rc); + rc.StateMode = ResolutionContext.State.StateLess; + Expr.Resolve(rc); + rc.StateMode = ResolutionContext.State.Single; + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from postcondition of Expr.Typecheck + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "axioms must be of type bool"); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAxiom(this); + } + } + + public abstract class NamedDeclaration : Declaration { + private string/*!*/ name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result() != null); + + return this.name; + } + set { + Contract.Requires(value != null); + this.name = value; + } + } + + public int TimeLimit + { + get + { + int tl = CommandLineOptions.Clo.ProverKillTime; + CheckIntAttribute("timeLimit", ref tl); + return tl; + } + } + + public NamedDeclaration(IToken/*!*/ tok, string/*!*/ name) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + this.name = name; + } + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(Name); + } + } + + public class TypeCtorDecl : NamedDeclaration { + public readonly int Arity; + + public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + this.Arity = Arity; + } + public TypeCtorDecl(IToken/*!*/ tok, string/*!*/ name, int Arity, QKeyValue kv) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + this.Arity = Arity; + this.Attributes = kv; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "type "); + EmitAttributes(stream); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); + for (int i = 0; i < Arity; ++i) + stream.Write(" _"); + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddType(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeCtorDecl(this); + } + } + + public class TypeSynonymDecl : NamedDeclaration { + private List/*!*/ typeParameters; + + public List TypeParameters { + get { + Contract.Ensures(Contract.Result>() != null); + return this.typeParameters; + } + set { + Contract.Requires(value != null); + this.typeParameters = value; + } + } + + private Type/*!*/ body; + + public Type Body { + get { + Contract.Ensures(Contract.Result() != null); + return this.body; + } + set { + Contract.Requires(value != null); + this.body = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.body != null); + Contract.Invariant(this.typeParameters != null); + } + + public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, + List/*!*/ typeParams, Type/*!*/ body) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(body != null); + this.typeParameters = typeParams; + this.body = body; + } + public TypeSynonymDecl(IToken/*!*/ tok, string/*!*/ name, + List/*!*/ typeParams, Type/*!*/ body, QKeyValue kv) + : base(tok, name) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(body != null); + this.typeParameters = typeParams; + this.body = body; + this.Attributes = kv; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "type "); + EmitAttributes(stream); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(Name)); + if (TypeParameters.Count > 0) + stream.Write(" "); + TypeParameters.Emit(stream, " "); + stream.Write(" = "); + Body.Emit(stream); + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddType(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(rc); + + int previousState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + Body = Body.ResolveType(rc); + } finally { + rc.TypeBinderState = previousState; + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + } + + public static void ResolveTypeSynonyms(List/*!*/ synonymDecls, ResolutionContext/*!*/ rc) { + Contract.Requires(cce.NonNullElements(synonymDecls)); + Contract.Requires(rc != null); + // then discover all dependencies between type synonyms + IDictionary/*!*/>/*!*/ deps = + new Dictionary/*!*/>(); + foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { + Contract.Assert(decl != null); + List/*!*/ declDeps = new List(); + FindDependencies(decl.Body, declDeps, rc); + deps.Add(decl, declDeps); + } + + List/*!*/ resolved = new List(); + + int unresolved = synonymDecls.Count - resolved.Count; + while (unresolved > 0) { + foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { + Contract.Assert(decl != null); + if (!resolved.Contains(decl) && + deps[decl].All(d => resolved.Contains(d))) { + decl.Resolve(rc); + resolved.Add(decl); + } + } + + int newUnresolved = synonymDecls.Count - resolved.Count; + if (newUnresolved < unresolved) { + // we are making progress + unresolved = newUnresolved; + } else { + // there have to be cycles in the definitions + foreach (TypeSynonymDecl/*!*/ decl in synonymDecls) { + Contract.Assert(decl != null); + if (!resolved.Contains(decl)) { + rc.Error(decl, + "type synonym could not be resolved because of cycles: {0}" + + " (replacing body with \"bool\" to continue resolving)", + decl.Name); + + // we simply replace the bodies of all remaining type + // synonyms with "bool" so that resolution can continue + decl.Body = Type.Bool; + decl.Resolve(rc); + } + } + + unresolved = 0; + } + } + } + + // determine a list of all type synonyms that occur in "type" + private static void FindDependencies(Type/*!*/ type, List/*!*/ deps, ResolutionContext/*!*/ rc) { + Contract.Requires(type != null); + Contract.Requires(cce.NonNullElements(deps)); + Contract.Requires(rc != null); + if (type.IsVariable || type.IsBasic) { + // nothing + } else if (type.IsUnresolved) { + UnresolvedTypeIdentifier/*!*/ unresType = type.AsUnresolved; + Contract.Assert(unresType != null); + TypeSynonymDecl dep = rc.LookUpTypeSynonym(unresType.Name); + if (dep != null) + deps.Add(dep); + foreach (Type/*!*/ subtype in unresType.Arguments) { + Contract.Assert(subtype != null); + FindDependencies(subtype, deps, rc); + } + } else if (type.IsMap) { + MapType/*!*/ mapType = type.AsMap; + Contract.Assert(mapType != null); + foreach (Type/*!*/ subtype in mapType.Arguments) { + Contract.Assert(subtype != null); + FindDependencies(subtype, deps, rc); + } + FindDependencies(mapType.Result, deps, rc); + } else if (type.IsCtor) { + // this can happen because we allow types to be resolved multiple times + CtorType/*!*/ ctorType = type.AsCtor; + Contract.Assert(ctorType != null); + foreach (Type/*!*/ subtype in ctorType.Arguments) { + Contract.Assert(subtype != null); + FindDependencies(subtype, deps, rc); + } + } else { + System.Diagnostics.Debug.Fail("Did not expect this type during resolution: " + + type); + } + } + + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeSynonymDecl(this); + } + } + + public abstract class Variable : NamedDeclaration { + private TypedIdent/*!*/ typedIdent; + + public TypedIdent TypedIdent { + get { + Contract.Ensures(Contract.Result() != null); + return this.typedIdent; + } + set { + Contract.Requires(value != null); + this.typedIdent = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.typedIdent != null); + } + + public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) + : base(tok, typedIdent.Name) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + this.typedIdent = typedIdent; + } + + public Variable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) + : base(tok, typedIdent.Name) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + this.typedIdent = typedIdent; + this.Attributes = kv; + } + + public abstract bool IsMutable { + get; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "var "); + EmitVitals(stream, level, true); + stream.WriteLine(";"); + } + public void EmitVitals(TokenTextWriter stream, int level, bool emitAttributes) { + Contract.Requires(stream != null); + if (emitAttributes) { + EmitAttributes(stream); + } + if (CommandLineOptions.Clo.PrintWithUniqueASTIds && this.TypedIdent.HasName) { + stream.Write("h{0}^^", this.GetHashCode()); // the idea is that this will prepend the name printed by TypedIdent.Emit + } + this.TypedIdent.Emit(stream); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + this.TypedIdent.Resolve(rc); + } + public void ResolveWhere(ResolutionContext rc) { + Contract.Requires(rc != null); + if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && this.TypedIdent.WhereExpr != null) + { + rc.Error(tok, "assumption variable may not be declared with a where clause"); + } + if (this.TypedIdent.WhereExpr != null) { + this.TypedIdent.WhereExpr.Resolve(rc); + } + ResolveAttributes(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + this.TypedIdent.Typecheck(tc); + if (QKeyValue.FindBoolAttribute(Attributes, "assumption") && !this.TypedIdent.Type.IsBool) + { + tc.Error(tok, "assumption variable must be of type 'bool'"); + } + } + } + + public class VariableComparer : IComparer { + public int Compare(object a, object b) { + Variable A = a as Variable; + Variable B = b as Variable; + if (A == null || B == null) { + throw new ArgumentException("VariableComparer works only on objects of type Variable"); + } + return cce.NonNull(A.Name).CompareTo(B.Name); + } + } + + // class to specify the <:-parents of the values of constants + public class ConstantParent { + public readonly IdentifierExpr/*!*/ Parent; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Parent != null); + } + + // if true, the sub-dag underneath this constant-parent edge is + // disjoint from all other unique sub-dags + public readonly bool Unique; + + public ConstantParent(IdentifierExpr parent, bool unique) { + Contract.Requires(parent != null); + Parent = parent; + Unique = unique; + } + } + + public class Constant : Variable { + // when true, the value of this constant is meant to be distinct + // from all other constants. + public readonly bool Unique; + + // the <:-parents of the value of this constant. If the field is + // null, no information about the parents is provided, which means + // that the parental situation is unconstrained. + public readonly ReadOnlyCollection Parents; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(Parents, true)); + } + + // if true, it is assumed that the immediate <:-children of the + // value of this constant are completely specified + public readonly bool ChildrenComplete; + + public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) + : base(tok, typedIdent) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + Contract.Requires(typedIdent.Name != null && (!typedIdent.HasName || typedIdent.Name.Length > 0)); + Contract.Requires(typedIdent.WhereExpr == null); + this.Unique = true; + this.Parents = null; + this.ChildrenComplete = false; + } + public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, bool unique) + : base(tok, typedIdent) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); + Contract.Requires(typedIdent.WhereExpr == null); + this.Unique = unique; + this.Parents = null; + this.ChildrenComplete = false; + } + public Constant(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, + bool unique, + IEnumerable parents, bool childrenComplete, + QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + Contract.Requires(cce.NonNullElements(parents, true)); + Contract.Requires(typedIdent.Name != null && typedIdent.Name.Length > 0); + Contract.Requires(typedIdent.WhereExpr == null); + this.Unique = unique; + this.Parents = parents == null ? null : new ReadOnlyCollection(parents.ToList()); + this.ChildrenComplete = childrenComplete; + } + public override bool IsMutable { + get { + return false; + } + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "const "); + EmitAttributes(stream); + if (this.Unique) { + stream.Write(this, level, "unique "); + } + EmitVitals(stream, level, false); + + if (Parents != null || ChildrenComplete) { + stream.Write(this, level, " extends"); + string/*!*/ sep = " "; + foreach (ConstantParent/*!*/ p in cce.NonNull(Parents)) { + Contract.Assert(p != null); + stream.Write(this, level, sep); + sep = ", "; + if (p.Unique) + stream.Write(this, level, "unique "); + p.Parent.Emit(stream); + } + if (ChildrenComplete) + stream.Write(this, level, " complete"); + } + + stream.WriteLine(";"); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, true); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + base.Resolve(rc); + if (Parents != null) { + foreach (ConstantParent/*!*/ p in Parents) { + Contract.Assert(p != null); + p.Parent.Resolve(rc); + if (p.Parent.Decl != null && !(p.Parent.Decl is Constant)) + rc.Error(p.Parent, "the parent of a constant has to be a constant"); + if (this.Equals(p.Parent.Decl)) + rc.Error(p.Parent, "constant cannot be its own parent"); + } + } + + // check that no parent occurs twice + // (could be optimised) + if (Parents != null) { + for (int i = 0; i < Parents.Count; ++i) { + if (Parents[i].Parent.Decl != null) { + for (int j = i + 1; j < Parents.Count; ++j) { + if (Parents[j].Parent.Decl != null && + cce.NonNull(Parents[i].Parent.Decl).Equals(Parents[j].Parent.Decl)) + rc.Error(Parents[j].Parent, + "{0} occurs more than once as parent", + Parents[j].Parent.Decl); + } + } + } + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + base.Typecheck(tc); + + if (Parents != null) { + foreach (ConstantParent/*!*/ p in Parents) { + Contract.Assert(p != null); + p.Parent.Typecheck(tc); + if (!cce.NonNull(p.Parent.Decl).TypedIdent.Type.Unify(this.TypedIdent.Type)) + tc.Error(p.Parent, + "parent of constant has incompatible type ({0} instead of {1})", + p.Parent.Decl.TypedIdent.Type, this.TypedIdent.Type); + } + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitConstant(this); + } + } + public class GlobalVariable : Variable { + public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent) + : base(tok, typedIdent) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + } + public GlobalVariable(IToken/*!*/ tok, TypedIdent/*!*/ typedIdent, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(tok != null); + Contract.Requires(typedIdent != null); + } + public override bool IsMutable { + get { + return true; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, true); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitGlobalVariable(this); + } + } + public class Formal : Variable { + public bool InComing; + public Formal(IToken tok, TypedIdent typedIdent, bool incoming, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + InComing = incoming; + } + public Formal(IToken tok, TypedIdent typedIdent, bool incoming) + : this(tok, typedIdent, incoming, null) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + } + public override bool IsMutable { + get { + return !InComing; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, false); + } + + /// + /// Given a sequence of Formal declarations, returns sequence of Formals like the given one but without where clauses + /// and without any attributes. + /// The Type of each Formal is cloned. + /// + public static List StripWhereClauses(List w) { + Contract.Requires(w != null); + Contract.Ensures(Contract.Result>() != null); + List s = new List(); + foreach (Variable/*!*/ v in w) { + Contract.Assert(v != null); + Formal f = (Formal)v; + TypedIdent ti = f.TypedIdent; + s.Add(new Formal(f.tok, new TypedIdent(ti.tok, ti.Name, ti.Type.CloneUnresolved()), f.InComing, null)); + } + return s; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitFormal(this); + } + } + public class LocalVariable : Variable { + public LocalVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + } + public LocalVariable(IToken tok, TypedIdent typedIdent) + : base(tok, typedIdent, null) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + } + public override bool IsMutable { + get { + return true; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, false); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitLocalVariable(this); + } + } + public class Incarnation : LocalVariable { + public int incarnationNumber; + public Incarnation(Variable/*!*/ var, int i) : + base( + var.tok, + new TypedIdent(var.TypedIdent.tok, var.TypedIdent.Name + "@" + i, var.TypedIdent.Type) + ) { + Contract.Requires(var != null); + incarnationNumber = i; + } + + } + public class BoundVariable : Variable { + public BoundVariable(IToken tok, TypedIdent typedIdent) + : base(tok, typedIdent) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + Contract.Requires(typedIdent.WhereExpr == null); + } + public BoundVariable(IToken tok, TypedIdent typedIdent, QKeyValue kv) + : base(tok, typedIdent, kv) { + Contract.Requires(typedIdent != null); + Contract.Requires(tok != null); + Contract.Requires(typedIdent.WhereExpr == null); + } + public override bool IsMutable { + get { + return false; + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddVariable(this, false); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBoundVariable(this); + } + } + + public abstract class DeclWithFormals : NamedDeclaration { + public List/*!*/ TypeParameters; + + private /*readonly--except in StandardVisitor*/ List/*!*/ inParams, outParams; + + public List/*!*/ InParams { + get { + Contract.Ensures(Contract.Result>() != null); + return this.inParams; + } + set { + Contract.Requires(value != null); + this.inParams = value; + } + } + + public List/*!*/ OutParams + { + get { + Contract.Ensures(Contract.Result>() != null); + return this.outParams; + } + set { + Contract.Requires(value != null); + this.outParams = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(TypeParameters != null); + Contract.Invariant(this.inParams != null); + Contract.Invariant(this.outParams != null); + } + + public DeclWithFormals(IToken tok, string name, List typeParams, + List inParams, List outParams) + : base(tok, name) { + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + this.TypeParameters = typeParams; + this.inParams = inParams; + this.outParams = outParams; + } + + protected DeclWithFormals(DeclWithFormals that) + : base(that.tok, cce.NonNull(that.Name)) { + Contract.Requires(that != null); + this.TypeParameters = that.TypeParameters; + this.inParams = cce.NonNull(that.InParams); + this.outParams = cce.NonNull(that.OutParams); + } + + public byte[] MD5Checksum_; + public byte[] MD5Checksum + { + get + { + if (MD5Checksum_ == null) + { + var c = Checksum; + if (c != null) + { + MD5Checksum_ = System.Security.Cryptography.MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(c)); + } + } + return MD5Checksum_; + } + } + + public byte[] MD5DependencyChecksum_; + public byte[] MD5DependencyChecksum + { + get + { + Contract.Requires(DependenciesCollected); + + if (MD5DependencyChecksum_ == null && MD5Checksum != null) + { + var c = MD5Checksum; + var transFuncDeps = new HashSet(); + if (procedureDependencies != null) + { + foreach (var p in procedureDependencies) + { + if (p.FunctionDependencies != null) + { + foreach (var f in p.FunctionDependencies) + { + transFuncDeps.Add(f); + } + } + var pc = p.MD5Checksum; + if (pc == null) { return null; } + c = ChecksumHelper.CombineChecksums(c, pc, true); + } + } + if (FunctionDependencies != null) + { + foreach (var f in FunctionDependencies) + { + transFuncDeps.Add(f); + } + } + var q = new Queue(transFuncDeps); + while (q.Any()) + { + var f = q.Dequeue(); + var fc = f.MD5Checksum; + if (fc == null) { return null; } + c = ChecksumHelper.CombineChecksums(c, fc, true); + if (f.FunctionDependencies != null) + { + foreach (var d in f.FunctionDependencies) + { + if (!transFuncDeps.Contains(d)) + { + transFuncDeps.Add(d); + q.Enqueue(d); + } + } + } + } + MD5DependencyChecksum_ = c; + } + return MD5DependencyChecksum_; + } + } + + public string Checksum + { + get + { + return FindStringAttribute("checksum"); + } + } + + string dependencyChecksum; + public string DependencyChecksum + { + get + { + if (dependencyChecksum == null && DependenciesCollected && MD5DependencyChecksum != null) + { + dependencyChecksum = BitConverter.ToString(MD5DependencyChecksum); + } + return dependencyChecksum; + } + } + + public bool DependenciesCollected { get; set; } + + ISet procedureDependencies; + + public ISet ProcedureDependencies + { + get { return procedureDependencies; } + } + + public void AddProcedureDependency(Procedure procedure) + { + Contract.Requires(procedure != null); + + if (procedureDependencies == null) + { + procedureDependencies = new HashSet(); + } + procedureDependencies.Add(procedure); + } + + ISet functionDependencies; + + public ISet FunctionDependencies + { + get { return functionDependencies; } + } + + public void AddFunctionDependency(Function function) + { + Contract.Requires(function != null); + + if (functionDependencies == null) + { + functionDependencies = new HashSet(); + } + functionDependencies.Add(function); + } + + public bool SignatureEquals(DeclWithFormals other) + { + Contract.Requires(other != null); + + string sig = null; + string otherSig = null; + using (var strWr = new System.IO.StringWriter()) + using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) + { + EmitSignature(tokTxtWr, this is Function); + sig = strWr.ToString(); + } + + using (var otherStrWr = new System.IO.StringWriter()) + using (var otherTokTxtWr = new TokenTextWriter("", otherStrWr, false, false)) + { + EmitSignature(otherTokTxtWr, other is Function); + otherSig = otherStrWr.ToString(); + } + return sig == otherSig; + } + + protected void EmitSignature(TokenTextWriter stream, bool shortRet) { + Contract.Requires(stream != null); + Type.EmitOptionalTypeParams(stream, TypeParameters); + stream.Write("("); + stream.push(); + InParams.Emit(stream, true); + stream.Write(")"); + stream.sep(); + + if (shortRet) { + Contract.Assert(OutParams.Count == 1); + stream.Write(" : "); + cce.NonNull(OutParams[0]).TypedIdent.Type.Emit(stream); + } else if (OutParams.Count > 0) { + stream.Write(" returns ("); + OutParams.Emit(stream, true); + stream.Write(")"); + } + stream.pop(); + } + + // Register all type parameters at the resolution context + protected void RegisterTypeParameters(ResolutionContext rc) { + Contract.Requires(rc != null); + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + } + + protected void SortTypeParams() { + List/*!*/ allTypes = new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()); + Contract.Assert(allTypes != null); + allTypes.AddRange(new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray())); + TypeParameters = Type.SortTypeParams(TypeParameters, allTypes, null); + } + + /// + /// Adds the given formals to the current variable context, and then resolves + /// the types of those formals. Does NOT resolve the where clauses of the + /// formals. + /// Relies on the caller to first create, and later tear down, that variable + /// context. + /// + /// + protected void RegisterFormals(List formals, ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Requires(formals != null); + foreach (Formal/*!*/ f in formals) { + Contract.Assert(f != null); + if (f.Name != TypedIdent.NoName) { + rc.AddVariable(f, false); + } + f.Resolve(rc); + } + } + + /// + /// Resolves the where clauses (and attributes) of the formals. + /// + /// + protected void ResolveFormals(List formals, ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Requires(formals != null); + foreach (Formal/*!*/ f in formals) { + Contract.Assert(f != null); + f.ResolveWhere(rc); + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(tc); + foreach (Formal/*!*/ p in InParams) { + Contract.Assert(p != null); + p.Typecheck(tc); + } + foreach (Formal/*!*/ p in OutParams) { + Contract.Assert(p != null); + p.Typecheck(tc); + } + } + } + + public class DatatypeConstructor : Function { + public List selectors; + public DatatypeMembership membership; + + public DatatypeConstructor(Function func) + : base(func.tok, func.Name, func.TypeParameters, func.InParams, func.OutParams[0], func.Comment, func.Attributes) + { + selectors = new List(); + } + + public override void Resolve(ResolutionContext rc) { + HashSet selectorNames = new HashSet(); + foreach (DatatypeSelector selector in selectors) { + if (selector.Name.StartsWith("#")) { + rc.Error(selector.tok, "The selector must be a non-empty string"); + } + else { + if (selectorNames.Contains(selector.Name)) + rc.Error(this.tok, "The selectors for a constructor must be distinct strings"); + else + selectorNames.Add(selector.Name); + } + } + base.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + CtorType outputType = this.OutParams[0].TypedIdent.Type as CtorType; + if (outputType == null || !outputType.IsDatatype()) { + tc.Error(tok, "The output type of a constructor must be a datatype"); + } + base.Typecheck(tc); + } + } + + public class DatatypeSelector : Function { + public Function constructor; + public int index; + public DatatypeSelector(Function constructor, int index) + : base(constructor.InParams[index].tok, + constructor.InParams[index].Name + "#" + constructor.Name, + new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, + new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.InParams[index].TypedIdent.Type), false)) + { + this.constructor = constructor; + this.index = index; + } + + public override void Emit(TokenTextWriter stream, int level) { } + } + + public class DatatypeMembership : Function { + public Function constructor; + public DatatypeMembership(Function constructor) + : base(constructor.tok, + "is#" + constructor.Name, + new List { new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true) }, + new Formal(constructor.tok, new TypedIdent(constructor.tok, "", Type.Bool), false)) + { + this.constructor = constructor; + } + + public override void Emit(TokenTextWriter stream, int level) { } + } + + public class Function : DeclWithFormals { + public string Comment; + + // the body is only set if the function is declared with {:inline} + public Expr Body; + public Axiom DefinitionAxiom; + + public IList otherDefinitionAxioms; + public IEnumerable OtherDefinitionAxioms + { + get + { + return otherDefinitionAxioms; + } + } + + public void AddOtherDefinitionAxiom(Axiom axiom) + { + Contract.Requires(axiom != null); + + if (otherDefinitionAxioms == null) + { + otherDefinitionAxioms = new List(); + } + otherDefinitionAxioms.Add(axiom); + } + + public bool doingExpansion; + + private bool neverTrigger; + private bool neverTriggerComputed; + + public string OriginalLambdaExprAsString; + + public Function(IToken tok, string name, List args, Variable result) + : this(tok, name, new List(), args, result, null) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, new List(), args, result, null); + } + public Function(IToken tok, string name, List typeParams, List args, Variable result) + : this(tok, name, typeParams, args, result, null) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, args, result, null); + } + public Function(IToken tok, string name, List args, Variable result, string comment) + : this(tok, name, new List(), args, result, comment) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, new List(), args, result, comment); + } + public Function(IToken tok, string name, List typeParams, List args, Variable/*!*/ result, string comment) + : base(tok, name, typeParams, args, new List { result }) { + Contract.Requires(result != null); + Contract.Requires(args != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + Comment = comment; + } + public Function(IToken tok, string name, List typeParams, List args, Variable result, + string comment, QKeyValue kv) + : this(tok, name, typeParams, args, result, comment) { + Contract.Requires(args != null); + Contract.Requires(result != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, args, result, comment); + this.Attributes = kv; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "function "); + EmitAttributes(stream); + if (Body != null && !QKeyValue.FindBoolAttribute(Attributes, "inline")) { + // Boogie inlines any function whose .Body field is non-null. The parser populates the .Body field + // is the :inline attribute is present, but if someone creates the Boogie file directly as an AST, then + // the :inline attribute may not be there. We'll make sure it's printed, so one can see that this means + // that the body will be inlined. + stream.Write("{:inline} "); + } + if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { + stream.Write("h{0}^^{1}", this.GetHashCode(), TokenTextWriter.SanitizeIdentifier(this.Name)); + } else { + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + EmitSignature(stream, true); + if (Body != null) { + stream.WriteLine(); + stream.WriteLine("{"); + stream.Write(level + 1, ""); + Body.Emit(stream); + stream.WriteLine(); + stream.WriteLine("}"); + } else { + stream.WriteLine(";"); + } + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddProcedure(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + int previousTypeBinderState = rc.TypeBinderState; + try { + RegisterTypeParameters(rc); + rc.PushVarContext(); + RegisterFormals(InParams, rc); + RegisterFormals(OutParams, rc); + ResolveAttributes(rc); + if (Body != null) + { + rc.StateMode = ResolutionContext.State.StateLess; + Body.Resolve(rc); + rc.StateMode = ResolutionContext.State.Single; + } + rc.PopVarContext(); + Type.CheckBoundVariableOccurrences(TypeParameters, + new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + this.tok, "function arguments", + rc); + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + SortTypeParams(); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + // PR: why was the base call left out previously? + base.Typecheck(tc); + // TypecheckAttributes(tc); + if (Body != null) { + Body.Typecheck(tc); + if (!cce.NonNull(Body.Type).Unify(cce.NonNull(OutParams[0]).TypedIdent.Type)) + tc.Error(Body, + "function body with invalid type: {0} (expected: {1})", + Body.Type, cce.NonNull(OutParams[0]).TypedIdent.Type); + } + } + + public bool NeverTrigger { + get { + if (!neverTriggerComputed) { + this.CheckBooleanAttribute("never_pattern", ref neverTrigger); + neverTriggerComputed = true; + } + return neverTrigger; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitFunction(this); + } + + public Axiom CreateDefinitionAxiom(Expr definition, QKeyValue kv = null) { + Contract.Requires(definition != null); + + List dummies = new List(); + List callArgs = new List(); + int i = 0; + foreach (Formal/*!*/ f in InParams) { + Contract.Assert(f != null); + string nm = f.TypedIdent.HasName ? f.TypedIdent.Name : "_" + i; + dummies.Add(new BoundVariable(f.tok, new TypedIdent(f.tok, nm, f.TypedIdent.Type))); + callArgs.Add(new IdentifierExpr(f.tok, nm)); + i++; + } + List/*!*/ quantifiedTypeVars = new List(); + foreach (TypeVariable/*!*/ t in TypeParameters) { + Contract.Assert(t != null); + quantifiedTypeVars.Add(new TypeVariable(tok, t.Name)); + } + + Expr call = new NAryExpr(tok, new FunctionCall(new IdentifierExpr(tok, Name)), callArgs); + // specify the type of the function, because it might be that + // type parameters only occur in the output type + call = Expr.CoerceType(tok, call, (Type)OutParams[0].TypedIdent.Type.Clone()); + Expr def = Expr.Binary(tok, BinaryOperator.Opcode.Eq, call, definition); + if (quantifiedTypeVars.Count != 0 || dummies.Count != 0) { + def = new ForallExpr(tok, quantifiedTypeVars, dummies, + kv, + new Trigger(tok, true, new List { call }, null), + def); + } + DefinitionAxiom = new Axiom(tok, def); + return DefinitionAxiom; + } + } + + public class Macro : Function { + public Macro(IToken tok, string name, List args, Variable result) + : base(tok, name, args, result) { } + } + + public class Requires : Absy, IPotentialErrorNode { + public readonly bool Free; + + private Expr/*!*/ _condition; + + public Expr/*!*/ Condition { + get { + Contract.Ensures(Contract.Result() != null); + return this._condition; + } + set { + Contract.Requires(value != null); + this._condition = value; + } + } + + public string Comment; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._condition != null); + } + + + // TODO: convert to use generics + private string errorData; + public string ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + + + private MiningStrategy errorDataEnhanced; + public MiningStrategy ErrorDataEnhanced { + get { + return errorDataEnhanced; + } + set { + errorDataEnhanced = value; + } + } + + public QKeyValue Attributes; + + public String ErrorMessage { + get { + return QKeyValue.FindStringAttribute(Attributes, "msg"); + } + } + + public Requires(IToken token, bool free, Expr condition, string comment, QKeyValue kv) + : base(token) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + this.Free = free; + this._condition = condition; + this.Comment = comment; + this.Attributes = kv; + } + + public Requires(IToken token, bool free, Expr condition, string comment) + : this(token, free, condition, comment, null) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + //:this(token, free, condition, comment, null); + } + + public Requires(bool free, Expr condition) + : this(Token.NoToken, free, condition, null) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, null); + } + + public Requires(bool free, Expr condition, string comment) + : this(Token.NoToken, free, condition, comment) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, comment); + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "{0}requires ", Free ? "free " : ""); + Cmd.EmitAttributes(stream, Attributes); + this.Condition.Emit(stream); + stream.WriteLine(";"); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + this.Condition.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + this.Condition.Typecheck(tc); + Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck + if (!this.Condition.Type.Unify(Type.Bool)) { + tc.Error(this, "preconditions must be of type bool"); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + return visitor.VisitRequires(this); + } + } + + public class Ensures : Absy, IPotentialErrorNode { + public readonly bool Free; + + private Expr/*!*/ _condition; + + public Expr/*!*/ Condition { + get { + Contract.Ensures(Contract.Result() != null); + return this._condition; + } + set { + Contract.Requires(value != null); + this._condition = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._condition != null); + } + + public string Comment; + + // TODO: convert to use generics + private string errorData; + public string ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + + private MiningStrategy errorDataEnhanced; + public MiningStrategy ErrorDataEnhanced { + get { + return errorDataEnhanced; + } + set { + errorDataEnhanced = value; + } + } + + public String ErrorMessage { + get { + return QKeyValue.FindStringAttribute(Attributes, "msg"); + } + } + + public QKeyValue Attributes; + + public Ensures(IToken token, bool free, Expr/*!*/ condition, string comment, QKeyValue kv) + : base(token) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + this.Free = free; + this._condition = condition; + this.Comment = comment; + this.Attributes = kv; + } + + public Ensures(IToken token, bool free, Expr condition, string comment) + : this(token, free, condition, comment, null) { + Contract.Requires(condition != null); + Contract.Requires(token != null); + //:this(token, free, condition, comment, null); + } + + public Ensures(bool free, Expr condition) + : this(Token.NoToken, free, condition, null) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, null); + } + + public Ensures(bool free, Expr condition, string comment) + : this(Token.NoToken, free, condition, comment) { + Contract.Requires(condition != null); + //:this(Token.NoToken, free, condition, comment); + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + if (Comment != null) { + stream.WriteLine(this, level, "// " + Comment); + } + stream.Write(this, level, "{0}ensures ", Free ? "free " : ""); + Cmd.EmitAttributes(stream, Attributes); + this.Condition.Emit(stream); + stream.WriteLine(";"); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + this.Condition.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + this.Condition.Typecheck(tc); + Contract.Assert(this.Condition.Type != null); // follows from postcondition of Expr.Typecheck + if (!this.Condition.Type.Unify(Type.Bool)) { + tc.Error(this, "postconditions must be of type bool"); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + return visitor.VisitEnsures(this); + } + } + + public class Procedure : DeclWithFormals { + public List/*!*/ Requires; + public List/*!*/ Modifies; + public List/*!*/ Ensures; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Requires != null); + Contract.Invariant(Modifies != null); + Contract.Invariant(Ensures != null); + Contract.Invariant(Summary != null); + } + + + // Abstract interpretation: Procedure-specific invariants... + [Rep] + public readonly ProcedureSummary/*!*/ Summary; + + public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, + List/*!*/ requires, List/*!*/ modifies, List/*!*/ ensures) + : this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(requires != null); + Contract.Requires(modifies != null); + Contract.Requires(ensures != null); + //:this(tok, name, typeParams, inParams, outParams, requires, modifies, ensures, null); + } + + public Procedure(IToken/*!*/ tok, string/*!*/ name, List/*!*/ typeParams, List/*!*/ inParams, List/*!*/ outParams, + List/*!*/ @requires, List/*!*/ @modifies, List/*!*/ @ensures, QKeyValue kv + ) + : base(tok, name, typeParams, inParams, outParams) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(@requires != null); + Contract.Requires(@modifies != null); + Contract.Requires(@ensures != null); + this.Requires = @requires; + this.Modifies = @modifies; + this.Ensures = @ensures; + this.Summary = new ProcedureSummary(); + this.Attributes = kv; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "procedure "); + EmitAttributes(stream); + stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + EmitSignature(stream, false); + stream.WriteLine(";"); + + level++; + + foreach (Requires/*!*/ e in this.Requires) { + Contract.Assert(e != null); + e.Emit(stream, level); + } + + if (this.Modifies.Count > 0) { + stream.Write(level, "modifies "); + this.Modifies.Emit(stream, false); + stream.WriteLine(";"); + } + + foreach (Ensures/*!*/ e in this.Ensures) { + Contract.Assert(e != null); + e.Emit(stream, level); + } + + if (!CommandLineOptions.Clo.IntraproceduralInfer) { + for (int s = 0; s < this.Summary.Count; s++) { + ProcedureSummaryEntry/*!*/ entry = cce.NonNull(this.Summary[s]); + stream.Write(level + 1, "// "); + stream.WriteLine(); + } + } + + stream.WriteLine(); + stream.WriteLine(); + } + + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.AddProcedure(this); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.PushVarContext(); + + foreach (IdentifierExpr/*!*/ ide in Modifies) { + Contract.Assert(ide != null); + ide.Resolve(rc); + } + + int previousTypeBinderState = rc.TypeBinderState; + try { + RegisterTypeParameters(rc); + + RegisterFormals(InParams, rc); + ResolveFormals(InParams, rc); // "where" clauses of in-parameters are resolved without the out-parameters in scope + foreach (Requires/*!*/ e in Requires) { + Contract.Assert(e != null); + e.Resolve(rc); + } + RegisterFormals(OutParams, rc); + ResolveFormals(OutParams, rc); // "where" clauses of out-parameters are resolved with both in- and out-parametes in scope + + rc.StateMode = ResolutionContext.State.Two; + foreach (Ensures/*!*/ e in Ensures) { + Contract.Assert(e != null); + e.Resolve(rc); + } + rc.StateMode = ResolutionContext.State.Single; + ResolveAttributes(rc); + + Type.CheckBoundVariableOccurrences(TypeParameters, + new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + this.tok, "procedure arguments", + rc); + + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + + rc.PopVarContext(); + + SortTypeParams(); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + base.Typecheck(tc); + foreach (IdentifierExpr/*!*/ ide in Modifies) { + Contract.Assert(ide != null); + Contract.Assume(ide.Decl != null); + if (!ide.Decl.IsMutable) { + tc.Error(this, "modifies list contains constant: {0}", ide.Name); + } + ide.Typecheck(tc); + } + foreach (Requires/*!*/ e in Requires) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + bool oldYields = tc.Yields; + tc.Yields = QKeyValue.FindBoolAttribute(Attributes, "yields"); + foreach (Ensures/*!*/ e in Ensures) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + tc.Yields = oldYields; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitProcedure(this); + } + } + + public class LoopProcedure : Procedure + { + public Implementation enclosingImpl; + private Dictionary blockMap; + private Dictionary blockLabelMap; + + public LoopProcedure(Implementation impl, Block header, + List inputs, List outputs, List globalMods) + : base(Token.NoToken, impl.Name + "_loop_" + header.ToString(), + new List(), inputs, outputs, + new List(), globalMods, new List()) + { + enclosingImpl = impl; + } + + public void setBlockMap(Dictionary bm) + { + blockMap = bm; + blockLabelMap = new Dictionary(); + foreach (var kvp in bm) + { + blockLabelMap.Add(kvp.Key.Label, kvp.Value); + } + } + + public Block getBlock(string label) + { + if (blockLabelMap.ContainsKey(label)) return blockLabelMap[label]; + return null; + } + } + + public class Implementation : DeclWithFormals { + public List/*!*/ LocVars; + [Rep] + public StmtList StructuredStmts; + [Rep] + public List/*!*/ Blocks; + public Procedure Proc; + + // Blocks before applying passification etc. + // Both are used only when /inline is set. + public List OriginalBlocks; + public List OriginalLocVars; + + public readonly ISet AssertionChecksums = new HashSet(ChecksumComparer.Default); + + public sealed class ChecksumComparer : IEqualityComparer + { + static IEqualityComparer defaultComparer; + public static IEqualityComparer Default + { + get + { + if (defaultComparer == null) + { + defaultComparer = new ChecksumComparer(); + } + return defaultComparer; + } + } + + public bool Equals(byte[] x, byte[] y) + { + if (x == null || y == null) + { + return x == y; + } + else + { + return x.SequenceEqual(y); + } + } + + public int GetHashCode(byte[] checksum) + { + if (checksum == null) + { + throw new ArgumentNullException("checksum"); + } + else + { + var result = 17; + for (int i = 0; i < checksum.Length; i++) + { + result = result * 23 + checksum[i]; + } + return result; + } + } + } + + public void AddAssertionChecksum(byte[] checksum) + { + Contract.Requires(checksum != null); + + if (AssertionChecksums != null) + { + AssertionChecksums.Add(checksum); + } + } + + public ISet AssertionChecksumsInCachedSnapshot { get; set; } + + public bool IsAssertionChecksumInCachedSnapshot(byte[] checksum) + { + Contract.Requires(AssertionChecksumsInCachedSnapshot != null); + + return AssertionChecksumsInCachedSnapshot.Contains(checksum); + } + + public IList RecycledFailingAssertions { get; protected set; } + + public void AddRecycledFailingAssertion(AssertCmd assertion) + { + if (RecycledFailingAssertions == null) + { + RecycledFailingAssertions = new List(); + } + RecycledFailingAssertions.Add(assertion); + } + + public Cmd ExplicitAssumptionAboutCachedPrecondition { get; set; } + + // Strongly connected components + private StronglyConnectedComponents scc; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(LocVars != null); + Contract.Invariant(cce.NonNullElements(Blocks)); + Contract.Invariant(cce.NonNullElements(OriginalBlocks, true)); + Contract.Invariant(cce.NonNullElements(scc, true)); + + } + private bool BlockPredecessorsComputed; + public bool StronglyConnectedComponentsComputed { + get { + return this.scc != null; + } + } + + public bool SkipVerification { + get { + bool verify = true; + cce.NonNull(this.Proc).CheckBooleanAttribute("verify", ref verify); + this.CheckBooleanAttribute("verify", ref verify); + if (!verify) { + return true; + } + + if (CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assert || + CommandLineOptions.Clo.ProcedureInlining == CommandLineOptions.Inlining.Assume) { + Expr inl = this.FindExprAttribute("inline"); + if (inl == null) + inl = this.Proc.FindExprAttribute("inline"); + if (inl != null && inl is LiteralExpr && ((LiteralExpr)inl).isBigNum && ((LiteralExpr)inl).asBigNum.Signum > 0) { + return true; + } + } + + if (CommandLineOptions.Clo.StratifiedInlining > 0) { + return !QKeyValue.FindBoolAttribute(Attributes, "entrypoint"); + } + + return false; + } + } + + public string Id + { + get + { + var id = FindStringAttribute("id"); + if (id == null) + { + id = Name + GetHashCode().ToString() + ":0"; + } + return id; + } + } + + public int Priority + { + get + { + int priority = 0; + CheckIntAttribute("priority", ref priority); + if (priority <= 0) + { + priority = 1; + } + return priority; + } + } + + public IDictionary ErrorChecksumToCachedError { get; private set; } + + public bool IsErrorChecksumInCachedSnapshot(byte[] checksum) + { + Contract.Requires(ErrorChecksumToCachedError != null); + + return ErrorChecksumToCachedError.ContainsKey(checksum); + } + + public void SetErrorChecksumToCachedError(IEnumerable> errors) + { + Contract.Requires(errors != null); + + ErrorChecksumToCachedError = new Dictionary(ChecksumComparer.Default); + foreach (var kv in errors) + { + ErrorChecksumToCachedError[kv.Item1] = kv.Item3; + if (kv.Item2 != null) + { + ErrorChecksumToCachedError[kv.Item2] = null; + } + } + } + + public bool HasCachedSnapshot + { + get + { + return ErrorChecksumToCachedError != null && AssertionChecksumsInCachedSnapshot != null; + } + } + + public bool AnyErrorsInCachedSnapshot + { + get + { + Contract.Requires(ErrorChecksumToCachedError != null); + + return ErrorChecksumToCachedError.Any(); + } + } + + IList injectedAssumptionVariables; + public IList InjectedAssumptionVariables + { + get + { + return injectedAssumptionVariables != null ? injectedAssumptionVariables : new List(); + } + } + + IList doomedInjectedAssumptionVariables; + public IList DoomedInjectedAssumptionVariables + { + get + { + return doomedInjectedAssumptionVariables != null ? doomedInjectedAssumptionVariables : new List(); + } + } + + public List RelevantInjectedAssumptionVariables(Dictionary incarnationMap) + { + return InjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); + } + + public List RelevantDoomedInjectedAssumptionVariables(Dictionary incarnationMap) + { + return DoomedInjectedAssumptionVariables.Where(v => { Expr e; if (incarnationMap.TryGetValue(v, out e)) { var le = e as LiteralExpr; return le == null || !le.IsTrue; } else { return false; } }).ToList(); + } + + public Expr ConjunctionOfInjectedAssumptionVariables(Dictionary incarnationMap, out bool isTrue) + { + Contract.Requires(incarnationMap != null); + + var vars = RelevantInjectedAssumptionVariables(incarnationMap).Select(v => incarnationMap[v]).ToList(); + isTrue = vars.Count == 0; + return LiteralExpr.BinaryTreeAnd(vars); + } + + public void InjectAssumptionVariable(LocalVariable variable, bool isDoomed = false) + { + LocVars.Add(variable); + if (isDoomed) + { + if (doomedInjectedAssumptionVariables == null) + { + doomedInjectedAssumptionVariables = new List(); + } + doomedInjectedAssumptionVariables.Add(variable); + } + else + { + if (injectedAssumptionVariables == null) + { + injectedAssumptionVariables = new List(); + } + injectedAssumptionVariables.Add(variable); + } + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, QKeyValue kv) + : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, kv, new Errors()) { + Contract.Requires(structuredStmts != null); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts) + : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()) { + Contract.Requires(structuredStmts != null); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, new Errors()); + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] StmtList structuredStmts, Errors errorHandler) + : this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler) { + Contract.Requires(errorHandler != null); + Contract.Requires(structuredStmts != null); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, structuredStmts, null, errorHandler); + } + + public Implementation(IToken/*!*/ tok, + string/*!*/ name, + List/*!*/ typeParams, + List/*!*/ inParams, + List/*!*/ outParams, + List/*!*/ localVariables, + [Captured] StmtList/*!*/ structuredStmts, + QKeyValue kv, + Errors/*!*/ errorHandler) + : base(tok, name, typeParams, inParams, outParams) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(typeParams != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(localVariables != null); + Contract.Requires(structuredStmts != null); + Contract.Requires(errorHandler != null); + LocVars = localVariables; + StructuredStmts = structuredStmts; + BigBlocksResolutionContext ctx = new BigBlocksResolutionContext(structuredStmts, errorHandler); + Blocks = ctx.Blocks; + BlockPredecessorsComputed = false; + scc = null; + Attributes = kv; + } + + public Implementation(IToken tok, string name, List typeParams, List inParams, List outParams, List localVariables, [Captured] List block) + : this(tok, name, typeParams, inParams, outParams, localVariables, block, null) { + Contract.Requires(cce.NonNullElements(block)); + Contract.Requires(localVariables != null); + Contract.Requires(outParams != null); + Contract.Requires(inParams != null); + Contract.Requires(typeParams != null); + Contract.Requires(name != null); + Contract.Requires(tok != null); + //:this(tok, name, typeParams, inParams, outParams, localVariables, block, null); + } + + public Implementation(IToken/*!*/ tok, + string/*!*/ name, + List/*!*/ typeParams, + List/*!*/ inParams, + List/*!*/ outParams, + List/*!*/ localVariables, + [Captured] List/*!*/ blocks, + QKeyValue kv) + : base(tok, name, typeParams, inParams, outParams) { + Contract.Requires(name != null); + Contract.Requires(inParams != null); + Contract.Requires(outParams != null); + Contract.Requires(localVariables != null); + Contract.Requires(cce.NonNullElements(blocks)); + LocVars = localVariables; + Blocks = blocks; + BlockPredecessorsComputed = false; + scc = null; + Attributes = kv; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "implementation "); + EmitAttributes(stream); + stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + EmitSignature(stream, false); + stream.WriteLine(); + + stream.WriteLine(level, "{0}", '{'); + + foreach (Variable/*!*/ v in this.LocVars) { + Contract.Assert(v != null); + v.Emit(stream, level + 1); + } + + if (this.StructuredStmts != null && !CommandLineOptions.Clo.PrintInstrumented && !CommandLineOptions.Clo.PrintInlined) { + if (this.LocVars.Count > 0) { + stream.WriteLine(); + } + if (CommandLineOptions.Clo.PrintUnstructured < 2) { + if (CommandLineOptions.Clo.PrintUnstructured == 1) { + stream.WriteLine(this, level + 1, "/*** structured program:"); + } + this.StructuredStmts.Emit(stream, level + 1); + if (CommandLineOptions.Clo.PrintUnstructured == 1) { + stream.WriteLine(level + 1, "**** end structured program */"); + } + } + } + + if (this.StructuredStmts == null || 1 <= CommandLineOptions.Clo.PrintUnstructured || + CommandLineOptions.Clo.PrintInstrumented || CommandLineOptions.Clo.PrintInlined) { + foreach (Block b in this.Blocks) { + b.Emit(stream, level + 1); + } + } + + stream.WriteLine(level, "{0}", '}'); + + stream.WriteLine(); + stream.WriteLine(); + } + public override void Register(ResolutionContext rc) { + //Contract.Requires(rc != null); + // nothing to register + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (Proc != null) { + // already resolved + return; + } + + DeclWithFormals dwf = rc.LookUpProcedure(cce.NonNull(this.Name)); + Proc = dwf as Procedure; + if (dwf == null) { + rc.Error(this, "implementation given for undeclared procedure: {0}", this.Name); + } else if (Proc == null) { + rc.Error(this, "implementations given for function, not procedure: {0}", this.Name); + } + + int previousTypeBinderState = rc.TypeBinderState; + try { + RegisterTypeParameters(rc); + + rc.PushVarContext(); + RegisterFormals(InParams, rc); + RegisterFormals(OutParams, rc); + + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Register(rc); + v.Resolve(rc); + } + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.ResolveWhere(rc); + } + + rc.PushProcedureContext(); + foreach (Block b in Blocks) { + b.Register(rc); + } + + ResolveAttributes(rc); + + rc.StateMode = ResolutionContext.State.Two; + foreach (Block b in Blocks) { + b.Resolve(rc); + } + rc.StateMode = ResolutionContext.State.Single; + + rc.PopProcedureContext(); + rc.PopVarContext(); + + Type.CheckBoundVariableOccurrences(TypeParameters, + new List(InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + new List(OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + this.tok, "implementation arguments", + rc); + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + SortTypeParams(); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + base.Typecheck(tc); + + Contract.Assume(this.Proc != null); + + if (this.TypeParameters.Count != Proc.TypeParameters.Count) { + tc.Error(this, "mismatched number of type parameters in procedure implementation: {0}", + this.Name); + } else { + // if the numbers of type parameters are different, it is + // difficult to compare the argument types + MatchFormals(this.InParams, Proc.InParams, "in", tc); + MatchFormals(this.OutParams, Proc.OutParams, "out", tc); + } + + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Typecheck(tc); + } + List oldFrame = tc.Frame; + bool oldYields = tc.Yields; + tc.Frame = Proc.Modifies; + tc.Yields = QKeyValue.FindBoolAttribute(Proc.Attributes, "yields"); + foreach (Block b in Blocks) { + b.Typecheck(tc); + } + Contract.Assert(tc.Frame == Proc.Modifies); + tc.Frame = oldFrame; + tc.Yields = oldYields; + } + void MatchFormals(List/*!*/ implFormals, List/*!*/ procFormals, string/*!*/ inout, TypecheckingContext/*!*/ tc) { + Contract.Requires(implFormals != null); + Contract.Requires(procFormals != null); + Contract.Requires(inout != null); + Contract.Requires(tc != null); + if (implFormals.Count != procFormals.Count) { + tc.Error(this, "mismatched number of {0}-parameters in procedure implementation: {1}", + inout, this.Name); + } else { + // unify the type parameters so that types can be compared + Contract.Assert(Proc != null); + Contract.Assert(this.TypeParameters.Count == Proc.TypeParameters.Count); + + IDictionary/*!*/ subst1 = + new Dictionary(); + IDictionary/*!*/ subst2 = + new Dictionary(); + + for (int i = 0; i < this.TypeParameters.Count; ++i) { + TypeVariable/*!*/ newVar = + new TypeVariable(Token.NoToken, Proc.TypeParameters[i].Name); + Contract.Assert(newVar != null); + subst1.Add(Proc.TypeParameters[i], newVar); + subst2.Add(this.TypeParameters[i], newVar); + } + + for (int i = 0; i < implFormals.Count; i++) { + // the names of the formals are allowed to change from the proc to the impl + + // but types must be identical + Type t = cce.NonNull((Variable)implFormals[i]).TypedIdent.Type.Substitute(subst2); + Type u = cce.NonNull((Variable)procFormals[i]).TypedIdent.Type.Substitute(subst1); + if (!t.Equals(u)) { + string/*!*/ a = cce.NonNull((Variable)implFormals[i]).Name; + Contract.Assert(a != null); + string/*!*/ b = cce.NonNull((Variable)procFormals[i]).Name; + Contract.Assert(b != null); + string/*!*/ c; + if (a == b) { + c = a; + } else { + c = String.Format("{0} (named {1} in implementation)", b, a); + } + tc.Error(this, "mismatched type of {0}-parameter in implementation {1}: {2}", inout, this.Name, c); + } + } + } + } + + private Dictionary/*?*/ formalMap = null; + public void ResetImplFormalMap() { + this.formalMap = null; + } + public Dictionary/*!*/ GetImplFormalMap() { + Contract.Ensures(Contract.Result>() != null); + + if (this.formalMap != null) + return this.formalMap; + else { + Dictionary/*!*/ map = new Dictionary (InParams.Count + OutParams.Count); + + Contract.Assume(this.Proc != null); + Contract.Assume(InParams.Count == Proc.InParams.Count); + for (int i = 0; i < InParams.Count; i++) { + Variable/*!*/ v = InParams[i]; + Contract.Assert(v != null); + IdentifierExpr ie = new IdentifierExpr(v.tok, v); + Variable/*!*/ pv = Proc.InParams[i]; + Contract.Assert(pv != null); + map.Add(pv, ie); + } + System.Diagnostics.Debug.Assert(OutParams.Count == Proc.OutParams.Count); + for (int i = 0; i < OutParams.Count; i++) { + Variable/*!*/ v = cce.NonNull(OutParams[i]); + IdentifierExpr ie = new IdentifierExpr(v.tok, v); + Variable pv = cce.NonNull(Proc.OutParams[i]); + map.Add(pv, ie); + } + this.formalMap = map; + + if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { + Console.WriteLine("Implementation.GetImplFormalMap on {0}:", this.Name); + using (TokenTextWriter stream = new TokenTextWriter("", Console.Out, /*setTokens=*/false, /*pretty=*/ false)) { + foreach (var e in map) { + Console.Write(" "); + cce.NonNull((Variable/*!*/)e.Key).Emit(stream, 0); + Console.Write(" --> "); + cce.NonNull((Expr)e.Value).Emit(stream); + Console.WriteLine(); + } + } + } + + return map; + } + } + + /// + /// Return a collection of blocks that are reachable from the block passed as a parameter. + /// The block must be defined in the current implementation + /// + public ICollection GetConnectedComponents(Block startingBlock) { + Contract.Requires(startingBlock != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); + Contract.Assert(this.Blocks.Contains(startingBlock)); + + if (!this.BlockPredecessorsComputed) + ComputeStronglyConnectedComponents(); + +#if DEBUG_PRINT + System.Console.WriteLine("* Strongly connected components * \n{0} \n ** ", scc); +#endif + + foreach (ICollection component in cce.NonNull(this.scc)) { + foreach (Block/*!*/ b in component) { + Contract.Assert(b != null); + if (b == startingBlock) // We found the compontent that owns the startingblock + { + return component; + } + } + } + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // if we are here, it means that the block is not in one of the components. This is an error. + } + + /// + /// Compute the strongly connected compontents of the blocks in the implementation. + /// As a side effect, it also computes the "predecessor" relation for the block in the implementation + /// + override public void ComputeStronglyConnectedComponents() { + if (!this.BlockPredecessorsComputed) + ComputePredecessorsForBlocks(); + + Adjacency next = new Adjacency(Successors); + Adjacency prev = new Adjacency(Predecessors); + + this.scc = new StronglyConnectedComponents(this.Blocks, next, prev); + scc.Compute(); + + + foreach (Block/*!*/ block in this.Blocks) { + Contract.Assert(block != null); + block.Predecessors = new List(); + } + + } + + /// + /// Reset the abstract stated computed before + /// + override public void ResetAbstractInterpretationState() { + foreach (Block/*!*/ b in this.Blocks) { + Contract.Assert(b != null); + b.ResetAbstractInterpretationState(); + } + } + + /// + /// A private method used as delegate for the strongly connected components. + /// It return, given a node, the set of its successors + /// + private IEnumerable/**//*!*/ Successors(Block node) { + Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + + GotoCmd gotoCmd = node.TransferCmd as GotoCmd; + + if (gotoCmd != null) { // If it is a gotoCmd + Contract.Assert(gotoCmd.labelTargets != null); + + return gotoCmd.labelTargets; + } else { // otherwise must be a ReturnCmd + Contract.Assert(node.TransferCmd is ReturnCmd); + + return new List(); + } + } + + /// + /// A private method used as delegate for the strongly connected components. + /// It return, given a node, the set of its predecessors + /// + private IEnumerable/**//*!*/ Predecessors(Block node) { + Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + + Contract.Assert(this.BlockPredecessorsComputed); + + return node.Predecessors; + } + + /// + /// Compute the predecessor informations for the blocks + /// + public void ComputePredecessorsForBlocks() { + foreach (Block b in this.Blocks) { + b.Predecessors = new List(); + } + foreach (Block b in this.Blocks) { + GotoCmd gtc = b.TransferCmd as GotoCmd; + if (gtc != null) { + Contract.Assert(gtc.labelTargets != null); + foreach (Block/*!*/ dest in gtc.labelTargets) { + Contract.Assert(dest != null); + dest.Predecessors.Add(b); + } + } + } + this.BlockPredecessorsComputed = true; + } + + public void PruneUnreachableBlocks() { + ArrayList /*Block!*/ visitNext = new ArrayList /*Block!*/ (); + List reachableBlocks = new List(); + HashSet reachable = new HashSet(); // the set of elements in "reachableBlocks" + + visitNext.Add(this.Blocks[0]); + while (visitNext.Count != 0) { + Block b = cce.NonNull((Block)visitNext[visitNext.Count - 1]); + visitNext.RemoveAt(visitNext.Count - 1); + if (!reachable.Contains(b)) { + reachableBlocks.Add(b); + reachable.Add(b); + if (b.TransferCmd is GotoCmd) { + if (CommandLineOptions.Clo.PruneInfeasibleEdges) { + foreach (Cmd/*!*/ s in b.Cmds) { + Contract.Assert(s != null); + if (s is PredicateCmd) { + LiteralExpr e = ((PredicateCmd)s).Expr as LiteralExpr; + if (e != null && e.IsFalse) { + // This statement sequence will never reach the end, because of this "assume false" or "assert false". + // Hence, it does not reach its successors. + b.TransferCmd = new ReturnCmd(b.TransferCmd.tok); + goto NEXT_BLOCK; + } + } + } + } + // it seems that the goto statement at the end may be reached + foreach (Block succ in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) { + Contract.Assume(succ != null); + visitNext.Add(succ); + } + } + } + NEXT_BLOCK: { + } + } + + this.Blocks = reachableBlocks; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitImplementation(this); + } + + public void FreshenCaptureStates() { + + // Assume commands with the "captureState" attribute allow model states to be + // captured for error reporting. + // Some program transformations, such as loop unrolling, duplicate parts of the + // program, leading to "capture-state-assumes" being duplicated. This leads + // to ambiguity when getting a state from the model. + // This method replaces the key of every "captureState" attribute with something + // unique + + int FreshCounter = 0; + foreach(var b in Blocks) { + List newCmds = new List(); + for (int i = 0; i < b.Cmds.Count(); i++) { + var a = b.Cmds[i] as AssumeCmd; + if (a != null && (QKeyValue.FindStringAttribute(a.Attributes, "captureState") != null)) { + string StateName = QKeyValue.FindStringAttribute(a.Attributes, "captureState"); + newCmds.Add(new AssumeCmd(Token.NoToken, a.Expr, FreshenCaptureState(a.Attributes, FreshCounter))); + FreshCounter++; + } + else { + newCmds.Add(b.Cmds[i]); + } + } + b.Cmds = newCmds; + } + } + + private QKeyValue FreshenCaptureState(QKeyValue Attributes, int FreshCounter) { + // Returns attributes identical to Attributes, but: + // - reversed (for ease of implementation; should not matter) + // - with the value for "captureState" replaced by a fresh value + Contract.Requires(QKeyValue.FindStringAttribute(Attributes, "captureState") != null); + string FreshValue = QKeyValue.FindStringAttribute(Attributes, "captureState") + "$renamed$" + Name + "$" + FreshCounter; + + QKeyValue result = null; + while (Attributes != null) { + if (Attributes.Key.Equals("captureState")) { + result = new QKeyValue(Token.NoToken, Attributes.Key, new List() { FreshValue }, result); + } else { + result = new QKeyValue(Token.NoToken, Attributes.Key, Attributes.Params, result); + } + Attributes = Attributes.Next; + } + return result; + } + + } + + + public class TypedIdent : Absy { + public const string NoName = ""; + + private string/*!*/ _name; + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result() != null); + return this._name; + } + set { + Contract.Requires(value != null); + this._name = value; + } + } + + private Type/*!*/ _type; + + public Type/*!*/ Type { + get { + Contract.Ensures(Contract.Result() != null); + return this._type; + } + set { + Contract.Requires(value != null); + this._type = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._name != null); + Contract.Invariant(this._type != null); + } + + public Expr WhereExpr; + // [NotDelayed] + public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type) + : this(tok, name, type, null) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(type != null); + Contract.Ensures(this.WhereExpr == null); //PM: needed to verify BoogiePropFactory.FreshBoundVariable + //:this(tok, name, type, null); // here for aesthetic reasons + } + // [NotDelayed] + public TypedIdent(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, Expr whereExpr) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(type != null); + Contract.Ensures(this.WhereExpr == whereExpr); + this._name = name; + this._type = type; + this.WhereExpr = whereExpr; + } + public bool HasName { + get { + return this.Name != NoName; + } + } + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.SetToken(this); + stream.push(); + if (this.Name != NoName) { + stream.Write("{0}: ", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + this.Type.Emit(stream); + if (this.WhereExpr != null) { + stream.sep(); + stream.Write(" where "); + this.WhereExpr.Emit(stream); + } + stream.pop(); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + // NOTE: WhereExpr needs to be resolved by the caller, because the caller must provide a modified ResolutionContext + this.Type = this.Type.ResolveType(rc); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + // type variables can occur when working with polymorphic functions/procedures + // if (!this.Type.IsClosed) + // tc.Error(this, "free variables in type of an identifier: {0}", + // this.Type.FreeVariables); + if (this.WhereExpr != null) { + this.WhereExpr.Typecheck(tc); + Contract.Assert(this.WhereExpr.Type != null); // follows from postcondition of Expr.Typecheck + if (!this.WhereExpr.Type.Unify(Type.Bool)) { + tc.Error(this, "where clauses must be of type bool"); + } + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypedIdent(this); + } + } + + #region Helper methods for generic Sequences + + public static class TypeVariableSeqAlgorithms { + public static void AppendWithoutDups(this List tvs, List s1) { + Contract.Requires(s1 != null); + for (int i = 0; i < s1.Count; i++) { + TypeVariable/*!*/ next = s1[i]; + Contract.Assert(next != null); + if (!tvs.Contains(next)) + tvs.Add(next); + } + } + } + + public static class Emitter { + + public static void Emit(this List/*!*/ decls, TokenTextWriter stream) { + Contract.Requires(stream != null); + Contract.Requires(cce.NonNullElements(decls)); + bool first = true; + foreach (Declaration d in decls) { + if (d == null) + continue; + if (first) { + first = false; + } else { + stream.WriteLine(); + } + d.Emit(stream, 0); + } + } + + public static void Emit(this List ss, TokenTextWriter stream) { + Contract.Requires(stream != null); + string sep = ""; + foreach (string/*!*/ s in ss) { + Contract.Assert(s != null); + stream.Write(sep); + sep = ", "; + stream.Write(s); + } + } + + public static void Emit(this IList ts, TokenTextWriter stream) { + Contract.Requires(stream != null); + string sep = ""; + stream.push(); + foreach (Expr/*!*/ e in ts) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + stream.sep(); + e.Emit(stream); + } + stream.pop(); + } + + public static void Emit(this List ids, TokenTextWriter stream, bool printWhereComments) { + Contract.Requires(stream != null); + string sep = ""; + foreach (IdentifierExpr/*!*/ e in ids) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + + if (printWhereComments && e.Decl != null && e.Decl.TypedIdent.WhereExpr != null) { + stream.Write(" /* where "); + e.Decl.TypedIdent.WhereExpr.Emit(stream); + stream.Write(" */"); + } + } + } + + public static void Emit(this List vs, TokenTextWriter stream, bool emitAttributes) { + Contract.Requires(stream != null); + string sep = ""; + stream.push(); + foreach (Variable/*!*/ v in vs) { + Contract.Assert(v != null); + stream.Write(sep); + sep = ", "; + stream.sep(); + v.EmitVitals(stream, 0, emitAttributes); + } + stream.pop(); + } + + public static void Emit(this List tys, TokenTextWriter stream, string separator) { + Contract.Requires(separator != null); + Contract.Requires(stream != null); + string sep = ""; + foreach (Type/*!*/ v in tys) { + Contract.Assert(v != null); + stream.Write(sep); + sep = separator; + v.Emit(stream); + } + } + + public static void Emit(this List tvs, TokenTextWriter stream, string separator) { + Contract.Requires(separator != null); + Contract.Requires(stream != null); + string sep = ""; + foreach (TypeVariable/*!*/ v in tvs) { + Contract.Assert(v != null); + stream.Write(sep); + sep = separator; + v.Emit(stream); + } + } + + } + #endregion + + + #region Regular Expressions + // a data structure to recover the "program structure" from the flow graph + public abstract class RE : Cmd { + public RE() + : base(Token.NoToken) { + } + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + throw new NotImplementedException(); + } + } + public class AtomicRE : RE { + private Block/*!*/ _b; + + public Block b + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._b; + } + set + { + Contract.Requires(value != null); + this._b = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._b != null); + } + + public AtomicRE(Block block) { + Contract.Requires(block != null); + this._b = block; + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + b.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + b.Typecheck(tc); + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + b.Emit(stream, level); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAtomicRE(this); + } + } + public abstract class CompoundRE : RE { + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + return; + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + return; + } + } + public class Sequential : CompoundRE { + private RE/*!*/ _first; + + public RE/*!*/ first { + get { + Contract.Ensures(Contract.Result() != null); + return this._first; + } + set { + Contract.Requires(value != null); + this._first = value; + } + } + + private RE/*!*/ _second; + + public RE/*!*/ second { + get { + Contract.Ensures(Contract.Result() != null); + return this._second; + } + set { + Contract.Requires(value != null); + this._second = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._first != null); + Contract.Invariant(this._second != null); + } + + public Sequential(RE first, RE second) { + Contract.Requires(first != null); + Contract.Requires(second != null); + this._first = first; + this._second = second; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(); + stream.WriteLine("{0};", Indent(stream.UseForComputingChecksums ? 0 : level)); + first.Emit(stream, level + 1); + second.Emit(stream, level + 1); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitSequential(this); + } + } + public class Choice : CompoundRE { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._rs != null); + } + + private List/*!*/ _rs; + + public List/*!*/ rs { //Rename this (and _rs) if possible + get { + Contract.Ensures(Contract.Result>() != null); + return this._rs; + } + set { + Contract.Requires(value != null); + this._rs = value; + } + } + + public Choice(List operands) { + Contract.Requires(operands != null); + this._rs = operands; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(); + stream.WriteLine("{0}[]", Indent(stream.UseForComputingChecksums ? 0 : level)); + foreach (RE/*!*/ r in rs) { + Contract.Assert(r != null); + r.Emit(stream, level + 1); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitChoice(this); + } + } + public class DAG2RE { + public static RE Transform(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result() != null); + TransferCmd tc = b.TransferCmd; + if (tc is ReturnCmd) { + return new AtomicRE(b); + } else if (tc is GotoCmd) { + GotoCmd/*!*/ g = (GotoCmd)tc; + Contract.Assert(g != null); + Contract.Assume(g.labelTargets != null); + if (g.labelTargets.Count == 1) { + return new Sequential(new AtomicRE(b), Transform(cce.NonNull(g.labelTargets[0]))); + } else { + List rs = new List(); + foreach (Block/*!*/ target in g.labelTargets) { + Contract.Assert(target != null); + RE r = Transform(target); + rs.Add(r); + } + RE second = new Choice(rs); + return new Sequential(new AtomicRE(b), second); + } + } else { + Contract.Assume(false); + throw new cce.UnreachableException(); + } + } + } + + #endregion + + // NOTE: This class is here for convenience, since this file's + // classes are used pretty much everywhere. + + public class BoogieDebug { + public static bool DoPrinting = false; + + public static void Write(string format, params object[] args) { + Contract.Requires(args != null); + Contract.Requires(format != null); + if (DoPrinting) { + Console.Error.Write(format, args); + } + } + + public static void WriteLine(string format, params object[] args) { + Contract.Requires(args != null); + Contract.Requires(format != null); + if (DoPrinting) { + Console.Error.WriteLine(format, args); + } + } + + public static void WriteLine() { + if (DoPrinting) { + Console.Error.WriteLine(); + } + } + } +} diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs index f659f9ea..404945a9 100644 --- a/Source/Core/AbsyCmd.cs +++ b/Source/Core/AbsyCmd.cs @@ -1,3482 +1,3482 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using System.Linq; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - using Set = GSet; - - - //--------------------------------------------------------------------- - // BigBlock - public class BigBlock { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - Contract.Invariant(Anonymous || this.labelName != null); - Contract.Invariant(this._ec == null || this._tc == null); - Contract.Invariant(this._simpleCmds != null); - } - - public readonly IToken/*!*/ tok; - - public readonly bool Anonymous; - - private string labelName; - - public string LabelName - { - get - { - Contract.Ensures(Anonymous || Contract.Result() != null); - return this.labelName; - } - set - { - Contract.Requires(Anonymous || value != null); - this.labelName = value; - } - } - - [Rep] - private List/*!*/ _simpleCmds; - - public List/*!*/ simpleCmds - { - get - { - Contract.Ensures(Contract.Result>() != null); - return this._simpleCmds; - } - set - { - Contract.Requires(value != null); - this._simpleCmds = value; - } - } - - private StructuredCmd _ec; - - public StructuredCmd ec - { - get - { - return this._ec; - } - set - { - Contract.Requires(value == null || this.tc == null); - this._ec = value; - } - } - - private TransferCmd _tc; - - public TransferCmd tc - { - get - { - return this._tc; - } - set - { - Contract.Requires(value == null || this.ec == null); - this._tc = value; - } - } - - public BigBlock successorBigBlock; // semantic successor (may be a back-edge, pointing back to enclosing while statement); null if successor is end of procedure body (or if field has not yet been initialized) - - public BigBlock(IToken tok, string labelName, [Captured] List simpleCmds, StructuredCmd ec, TransferCmd tc) { - Contract.Requires(simpleCmds != null); - Contract.Requires(tok != null); - Contract.Requires(ec == null || tc == null); - this.tok = tok; - this.Anonymous = labelName == null; - this.labelName = labelName; - this._simpleCmds = simpleCmds; - this._ec = ec; - this._tc = tc; - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - if (!Anonymous) { - stream.WriteLine(level, "{0}:", - CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.LabelName) : this.LabelName); - } - - foreach (Cmd/*!*/ c in this.simpleCmds) { - Contract.Assert(c != null); - c.Emit(stream, level + 1); - } - - if (this.ec != null) { - this.ec.Emit(stream, level + 1); - } else if (this.tc != null) { - this.tc.Emit(stream, level + 1); - } - } - } - - public class StmtList { - [Rep] - private readonly List/*!*/ bigBlocks; - - public IList/*!*/ BigBlocks - { - get - { - Contract.Ensures(Contract.Result>() != null); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this.bigBlocks.AsReadOnly(); - } - } - - public List PrefixCommands; - public readonly IToken/*!*/ EndCurly; - public StmtList ParentContext; - public BigBlock ParentBigBlock; - - private readonly HashSet/*!*/ labels = new HashSet(); - - public void AddLabel(string label) - { - labels.Add(label); - } - - public IEnumerable/*!*/ Labels - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result/*!*/>())); - return this.labels.AsEnumerable(); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(EndCurly != null); - Contract.Invariant(cce.NonNullElements(this.bigBlocks)); - Contract.Invariant(cce.NonNullElements(this.labels)); - } - - public StmtList(IList/*!*/ bigblocks, IToken endCurly) { - Contract.Requires(endCurly != null); - Contract.Requires(cce.NonNullElements(bigblocks)); - Contract.Requires(bigblocks.Count > 0); - this.bigBlocks = new List(bigblocks); - this.EndCurly = endCurly; - } - - // prints the list of statements, not the surrounding curly braces - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - bool needSeperator = false; - foreach (BigBlock b in BigBlocks) { - Contract.Assert(b != null); - Contract.Assume(cce.IsPeerConsistent(b)); - if (needSeperator) { - stream.WriteLine(); - } - b.Emit(stream, level); - needSeperator = true; - } - } - - /// - /// Tries to insert the commands "prefixCmds" at the beginning of the first block - /// of the StmtList, and returns "true" iff it succeeded. - /// In the event of success, the "suggestedLabel" returns as the name of the - /// block inside StmtList where "prefixCmds" were inserted. This name may be the - /// same as the one passed in, in case this StmtList has no preference as to what - /// to call its first block. In the event of failure, "suggestedLabel" is returned - /// as its input value. - /// Note, to be conservative (that is, ignoring the possible optimization that this - /// method enables), this method can do nothing and return false. - /// - public bool PrefixFirstBlock([Captured] List prefixCmds, ref string suggestedLabel) { - Contract.Requires(suggestedLabel != null); - Contract.Requires(prefixCmds != null); - Contract.Ensures(Contract.Result() || cce.Owner.None(prefixCmds)); // "prefixCmds" is captured only on success - Contract.Assume(PrefixCommands == null); // prefix has not been used - - BigBlock bb0 = BigBlocks[0]; - if (prefixCmds.Count == 0) { - // This is always a success, since there is nothing to insert. Now, decide - // which name to use for the first block. - if (bb0.Anonymous) { - bb0.LabelName = suggestedLabel; - } else { - Contract.Assert(bb0.LabelName != null); - suggestedLabel = bb0.LabelName; - } - return true; - - } else { - // There really is something to insert. We can do this inline only if the first - // block is anonymous (which implies there is no branch to it from within the block). - if (bb0.Anonymous) { - PrefixCommands = prefixCmds; - bb0.LabelName = suggestedLabel; - return true; - } else { - return false; - } - } - } - } - - /// - /// The AST for Boogie structured commands was designed to support backward compatibility with - /// the Boogie unstructured commands. This has made the structured commands hard to construct. - /// The StmtListBuilder class makes it easier to build structured commands. - /// - public class StmtListBuilder { - List/*!*/ bigBlocks = new List(); - string label; - List simpleCmds; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(bigBlocks)); - } - - void Dump(StructuredCmd scmd, TransferCmd tcmd) { - Contract.Requires(scmd == null || tcmd == null); - Contract.Ensures(label == null && simpleCmds == null); - if (label == null && simpleCmds == null && scmd == null && tcmd == null) { - // nothing to do - } else { - if (simpleCmds == null) { - simpleCmds = new List(); - } - bigBlocks.Add(new BigBlock(Token.NoToken, label, simpleCmds, scmd, tcmd)); - label = null; - simpleCmds = null; - } - } - - /// - /// Collects the StmtList built so far and returns it. The StmtListBuilder should no longer - /// be used once this method has been invoked. - /// - public StmtList Collect(IToken endCurlyBrace) { - Contract.Requires(endCurlyBrace != null); - Contract.Ensures(Contract.Result() != null); - Dump(null, null); - if (bigBlocks.Count == 0) { - simpleCmds = new List(); // the StmtList constructor doesn't like an empty list of BigBlock's - Dump(null, null); - } - return new StmtList(bigBlocks, endCurlyBrace); - } - - public void Add(Cmd cmd) { - Contract.Requires(cmd != null); - if (simpleCmds == null) { - simpleCmds = new List(); - } - simpleCmds.Add(cmd); - } - - public void Add(StructuredCmd scmd) { - Contract.Requires(scmd != null); - Dump(scmd, null); - } - - public void Add(TransferCmd tcmd) { - Contract.Requires(tcmd != null); - Dump(null, tcmd); - } - - public void AddLabelCmd(string label) { - Contract.Requires(label != null); - Dump(null, null); - this.label = label; - } - - public void AddLocalVariable(string name) { - Contract.Requires(name != null); - // TODO - } - } - - class BigBlocksResolutionContext { - StmtList/*!*/ stmtList; - [Peer] - List blocks; - string/*!*/ prefix = "anon"; - int anon = 0; - int FreshAnon() - { - return anon++; - } - HashSet allLabels = new HashSet(); - Errors/*!*/ errorHandler; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(stmtList != null); - Contract.Invariant(cce.NonNullElements(blocks, true)); - Contract.Invariant(prefix != null); - Contract.Invariant(cce.NonNullElements(allLabels, true)); - Contract.Invariant(errorHandler != null); - } - - private void ComputeAllLabels(StmtList stmts) { - if (stmts == null) return; - foreach (BigBlock bb in stmts.BigBlocks) { - if (bb.LabelName != null) { - allLabels.Add(bb.LabelName); - } - ComputeAllLabels(bb.ec); - } - } - - private void ComputeAllLabels(StructuredCmd cmd) { - if (cmd == null) return; - if (cmd is IfCmd) { - IfCmd ifCmd = (IfCmd)cmd; - ComputeAllLabels(ifCmd.thn); - ComputeAllLabels(ifCmd.elseIf); - ComputeAllLabels(ifCmd.elseBlock); - } - else if (cmd is WhileCmd) { - WhileCmd whileCmd = (WhileCmd)cmd; - ComputeAllLabels(whileCmd.Body); - } - } - - public BigBlocksResolutionContext(StmtList stmtList, Errors errorHandler) { - Contract.Requires(errorHandler != null); - Contract.Requires(stmtList != null); - this.stmtList = stmtList; - this.errorHandler = errorHandler; - ComputeAllLabels(stmtList); - } - - public List/*!*/ Blocks { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - if (blocks == null) { - blocks = new List(); - - int startErrorCount = this.errorHandler.count; - // Check that all goto statements go to a label in allLabels, and no break statement to a non-enclosing loop. - // Also, determine a good value for "prefix". - CheckLegalLabels(stmtList, null, null); - - // fill in names of anonymous blocks - NameAnonymousBlocks(stmtList); - - // determine successor blocks - RecordSuccessors(stmtList, null); - - if (this.errorHandler.count == startErrorCount) { - // generate blocks from the big blocks - CreateBlocks(stmtList, null); - } - } - return blocks; - } - } - - void CheckLegalLabels(StmtList stmtList, StmtList parentContext, BigBlock parentBigBlock) { - Contract.Requires(stmtList != null); - Contract.Requires((parentContext == null) == (parentBigBlock == null)); - Contract.Requires(stmtList.ParentContext == null); // it hasn't been set yet - //modifies stmtList.*; - Contract.Ensures(stmtList.ParentContext == parentContext); - stmtList.ParentContext = parentContext; - stmtList.ParentBigBlock = parentBigBlock; - - // record the labels declared in this StmtList - foreach (BigBlock b in stmtList.BigBlocks) { - if (b.LabelName != null) { - string n = b.LabelName; - if (n.StartsWith(prefix)) { - if (prefix.Length < n.Length && n[prefix.Length] == '0') { - prefix += "1"; - } else { - prefix += "0"; - } - } - stmtList.AddLabel(b.LabelName); - } - } - - // check that labels in this and nested StmtList's are legal - foreach (BigBlock b in stmtList.BigBlocks) { - // goto's must reference blocks in enclosing blocks - if (b.tc is GotoCmd) { - GotoCmd g = (GotoCmd)b.tc; - foreach (string/*!*/ lbl in cce.NonNull(g.labelNames)) { - Contract.Assert(lbl != null); - /* - bool found = false; - for (StmtList sl = stmtList; sl != null; sl = sl.ParentContext) { - if (sl.Labels.Contains(lbl)) { - found = true; - break; - } - } - if (!found) { - this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined or out of reach"); - } - */ - if (!allLabels.Contains(lbl)) { - this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined"); - } - } - } - - // break labels must refer to an enclosing while statement - else if (b.ec is BreakCmd) { - BreakCmd bcmd = (BreakCmd)b.ec; - Contract.Assert(bcmd.BreakEnclosure == null); // it hasn't been initialized yet - bool found = false; - for (StmtList sl = stmtList; sl.ParentBigBlock != null; sl = sl.ParentContext) { - cce.LoopInvariant(sl != null); - BigBlock bb = sl.ParentBigBlock; - - if (bcmd.Label == null) { - // a label-less break statement breaks out of the innermost enclosing while statement - if (bb.ec is WhileCmd) { - bcmd.BreakEnclosure = bb; - found = true; - break; - } - } else if (bcmd.Label == bb.LabelName) { - // a break statement with a label can break out of both if statements and while statements - if (bb.simpleCmds.Count == 0) { - // this is a good target: the label refers to the if/while statement - bcmd.BreakEnclosure = bb; - } else { - // the label of bb refers to the first statement of bb, which in which case is a simple statement, not an if/while statement - this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); - } - found = true; // don't look any further, since we've found a matching label - break; - } - } - if (!found) { - if (bcmd.Label == null) { - this.errorHandler.SemErr(bcmd.tok, "Error: break statement is not inside a loop"); - } else { - this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); - } - } - } - - // recurse - else if (b.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)b.ec; - CheckLegalLabels(wcmd.Body, stmtList, b); - } else { - for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { - CheckLegalLabels(ifcmd.thn, stmtList, b); - if (ifcmd.elseBlock != null) { - CheckLegalLabels(ifcmd.elseBlock, stmtList, b); - } - } - } - } - } - - void NameAnonymousBlocks(StmtList stmtList) { - Contract.Requires(stmtList != null); - foreach (BigBlock b in stmtList.BigBlocks) { - if (b.LabelName == null) { - b.LabelName = prefix + FreshAnon(); - } - if (b.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)b.ec; - NameAnonymousBlocks(wcmd.Body); - } else { - for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { - NameAnonymousBlocks(ifcmd.thn); - if (ifcmd.elseBlock != null) { - NameAnonymousBlocks(ifcmd.elseBlock); - } - } - } - } - } - - void RecordSuccessors(StmtList stmtList, BigBlock successor) { - Contract.Requires(stmtList != null); - for (int i = stmtList.BigBlocks.Count; 0 <= --i; ) { - BigBlock big = stmtList.BigBlocks[i]; - big.successorBigBlock = successor; - - if (big.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)big.ec; - RecordSuccessors(wcmd.Body, big); - } else { - for (IfCmd ifcmd = big.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { - RecordSuccessors(ifcmd.thn, successor); - if (ifcmd.elseBlock != null) { - RecordSuccessors(ifcmd.elseBlock, successor); - } - } - } - - successor = big; - } - } - - // If the enclosing context is a loop, then "runOffTheEndLabel" is the loop head label; - // otherwise, it is null. - void CreateBlocks(StmtList stmtList, string runOffTheEndLabel) { - Contract.Requires(stmtList != null); - Contract.Requires(blocks != null); - List cmdPrefixToApply = stmtList.PrefixCommands; - - int n = stmtList.BigBlocks.Count; - foreach (BigBlock b in stmtList.BigBlocks) { - n--; - Contract.Assert(b.LabelName != null); - List theSimpleCmds; - if (cmdPrefixToApply == null) { - theSimpleCmds = b.simpleCmds; - } else { - theSimpleCmds = new List(); - theSimpleCmds.AddRange(cmdPrefixToApply); - theSimpleCmds.AddRange(b.simpleCmds); - cmdPrefixToApply = null; // now, we've used 'em up - } - - if (b.tc != null) { - // this BigBlock has the very same components as a Block - Contract.Assert(b.ec == null); - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, b.tc); - blocks.Add(block); - - } else if (b.ec == null) { - TransferCmd trCmd; - if (n == 0 && runOffTheEndLabel != null) { - // goto the given label instead of the textual successor block - trCmd = new GotoCmd(stmtList.EndCurly, new List { runOffTheEndLabel }); - } else { - trCmd = GotoSuccessor(stmtList.EndCurly, b); - } - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, trCmd); - blocks.Add(block); - - } else if (b.ec is BreakCmd) { - BreakCmd bcmd = (BreakCmd)b.ec; - Contract.Assert(bcmd.BreakEnclosure != null); - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, GotoSuccessor(b.ec.tok, bcmd.BreakEnclosure)); - blocks.Add(block); - - } else if (b.ec is WhileCmd) { - WhileCmd wcmd = (WhileCmd)b.ec; - var a = FreshAnon(); - string loopHeadLabel = prefix + a + "_LoopHead"; - string/*!*/ loopBodyLabel = prefix + a + "_LoopBody"; - string loopDoneLabel = prefix + a + "_LoopDone"; - - List ssBody = new List(); - List ssDone = new List(); - if (wcmd.Guard != null) { - var ac = new AssumeCmd(wcmd.tok, wcmd.Guard); - ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); - ssBody.Add(ac); - - ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard)); - ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); - ssDone.Add(ac); - } - - // Try to squeeze in ssBody into the first block of wcmd.Body - bool bodyGuardTakenCareOf = wcmd.Body.PrefixFirstBlock(ssBody, ref loopBodyLabel); - - // ... goto LoopHead; - Block block = new Block(b.tok, b.LabelName, theSimpleCmds, new GotoCmd(wcmd.tok, new List { loopHeadLabel })); - blocks.Add(block); - - // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody; - List ssHead = new List(); - foreach (PredicateCmd inv in wcmd.Invariants) { - ssHead.Add(inv); - } - block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List { loopDoneLabel, loopBodyLabel })); - blocks.Add(block); - - if (!bodyGuardTakenCareOf) { - // LoopBody: assume guard; goto firstLoopBlock; - block = new Block(wcmd.tok, loopBodyLabel, ssBody, new GotoCmd(wcmd.tok, new List { wcmd.Body.BigBlocks[0].LabelName })); - blocks.Add(block); - } - - // recurse to create the blocks for the loop body - CreateBlocks(wcmd.Body, loopHeadLabel); - - // LoopDone: assume !guard; goto loopSuccessor; - TransferCmd trCmd; - if (n == 0 && runOffTheEndLabel != null) { - // goto the given label instead of the textual successor block - trCmd = new GotoCmd(wcmd.tok, new List { runOffTheEndLabel }); - } else { - trCmd = GotoSuccessor(wcmd.tok, b); - } - block = new Block(wcmd.tok, loopDoneLabel, ssDone, trCmd); - blocks.Add(block); - - } else { - IfCmd ifcmd = (IfCmd)b.ec; - string predLabel = b.LabelName; - List predCmds = theSimpleCmds; - - for (; ifcmd != null; ifcmd = ifcmd.elseIf) { - var a = FreshAnon(); - string thenLabel = prefix + a + "_Then"; - Contract.Assert(thenLabel != null); - string elseLabel = prefix + a + "_Else"; - Contract.Assert(elseLabel != null); - - List ssThen = new List(); - List ssElse = new List(); - if (ifcmd.Guard != null) { - var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard); - ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); - ssThen.Add(ac); - - ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); - ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); - ssElse.Add(ac); - } - - // Try to squeeze in ssThen/ssElse into the first block of ifcmd.thn/ifcmd.elseBlock - bool thenGuardTakenCareOf = ifcmd.thn.PrefixFirstBlock(ssThen, ref thenLabel); - bool elseGuardTakenCareOf = false; - if (ifcmd.elseBlock != null) { - elseGuardTakenCareOf = ifcmd.elseBlock.PrefixFirstBlock(ssElse, ref elseLabel); - } - - // ... goto Then, Else; - Block block = new Block(b.tok, predLabel, predCmds, - new GotoCmd(ifcmd.tok, new List { thenLabel, elseLabel })); - blocks.Add(block); - - if (!thenGuardTakenCareOf) { - // Then: assume guard; goto firstThenBlock; - block = new Block(ifcmd.tok, thenLabel, ssThen, new GotoCmd(ifcmd.tok, new List { ifcmd.thn.BigBlocks[0].LabelName })); - blocks.Add(block); - } - - // recurse to create the blocks for the then branch - CreateBlocks(ifcmd.thn, n == 0 ? runOffTheEndLabel : null); - - if (ifcmd.elseBlock != null) { - Contract.Assert(ifcmd.elseIf == null); - if (!elseGuardTakenCareOf) { - // Else: assume !guard; goto firstElseBlock; - block = new Block(ifcmd.tok, elseLabel, ssElse, new GotoCmd(ifcmd.tok, new List { ifcmd.elseBlock.BigBlocks[0].LabelName })); - blocks.Add(block); - } - - // recurse to create the blocks for the else branch - CreateBlocks(ifcmd.elseBlock, n == 0 ? runOffTheEndLabel : null); - - } else if (ifcmd.elseIf != null) { - // this is an "else if" - predLabel = elseLabel; - predCmds = new List(); - if (ifcmd.Guard != null) { - var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); - ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); - predCmds.Add(ac); - } - - } else { - // no else alternative is specified, so else branch is just "skip" - // Else: assume !guard; goto ifSuccessor; - TransferCmd trCmd; - if (n == 0 && runOffTheEndLabel != null) { - // goto the given label instead of the textual successor block - trCmd = new GotoCmd(ifcmd.tok, new List { runOffTheEndLabel }); - } else { - trCmd = GotoSuccessor(ifcmd.tok, b); - } - block = new Block(ifcmd.tok, elseLabel, ssElse, trCmd); - blocks.Add(block); - } - } - } - } - } - - TransferCmd GotoSuccessor(IToken tok, BigBlock b) { - Contract.Requires(b != null); - Contract.Requires(tok != null); - Contract.Ensures(Contract.Result() != null); - if (b.successorBigBlock != null) { - return new GotoCmd(tok, new List { b.successorBigBlock.LabelName }); - } else { - return new ReturnCmd(tok); - } - } - } - - [ContractClass(typeof(StructuredCmdContracts))] - public abstract class StructuredCmd { - private IToken/*!*/ _tok; - - public IToken/*!*/ tok - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._tok; - } - set - { - Contract.Requires(value != null); - this._tok = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._tok != null); - } - - public StructuredCmd(IToken tok) { - Contract.Requires(tok != null); - this._tok = tok; - } - - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - } - [ContractClassFor(typeof(StructuredCmd))] - public abstract class StructuredCmdContracts : StructuredCmd { - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - public StructuredCmdContracts() :base(null){ - - } - } - - public class IfCmd : StructuredCmd { - public Expr Guard; - - private StmtList/*!*/ _thn; - - public StmtList/*!*/ thn - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._thn; - } - set - { - Contract.Requires(value != null); - this._thn = value; - } - } - - private IfCmd _elseIf; - - public IfCmd elseIf - { - get - { - return this._elseIf; - } - set - { - Contract.Requires(value == null || this.elseBlock == null); - this._elseIf = value; - } - } - - private StmtList _elseBlock; - - public StmtList elseBlock - { - get - { - return this._elseBlock; - } - set - { - Contract.Requires(value == null || this.elseIf == null); - this._elseBlock = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._thn != null); - Contract.Invariant(this._elseIf == null || this._elseBlock == null); - } - - public IfCmd(IToken/*!*/ tok, Expr guard, StmtList/*!*/ thn, IfCmd elseIf, StmtList elseBlock) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(thn != null); - Contract.Requires(elseIf == null || elseBlock == null); - this.Guard = guard; - this._thn = thn; - this._elseIf = elseIf; - this._elseBlock = elseBlock; - } - - public override void Emit(TokenTextWriter stream, int level) { - stream.Write(level, "if ("); - IfCmd/*!*/ ifcmd = this; - while (true) { - if (ifcmd.Guard == null) { - stream.Write("*"); - } else { - ifcmd.Guard.Emit(stream); - } - stream.WriteLine(")"); - - stream.WriteLine(level, "{"); - ifcmd.thn.Emit(stream, level + 1); - stream.WriteLine(level, "}"); - - if (ifcmd.elseIf != null) { - stream.Write(level, "else if ("); - ifcmd = ifcmd.elseIf; - continue; - } else if (ifcmd.elseBlock != null) { - stream.WriteLine(level, "else"); - stream.WriteLine(level, "{"); - ifcmd.elseBlock.Emit(stream, level + 1); - stream.WriteLine(level, "}"); - } - break; - } - } - } - - public class WhileCmd : StructuredCmd { - [Peer] - public Expr Guard; - public List/*!*/ Invariants; - public StmtList/*!*/ Body; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Body != null); - Contract.Invariant(cce.NonNullElements(Invariants)); - } - - - public WhileCmd(IToken tok, [Captured] Expr guard, List/*!*/ invariants, StmtList/*!*/ body) - : base(tok) { - Contract.Requires(cce.NonNullElements(invariants)); - Contract.Requires(body != null); - Contract.Requires(tok != null); - this.Guard = guard; - this.Invariants = invariants; - this.Body = body; - } - - public override void Emit(TokenTextWriter stream, int level) { - stream.Write(level, "while ("); - if (Guard == null) { - stream.Write("*"); - } else { - Guard.Emit(stream); - } - stream.WriteLine(")"); - - foreach (PredicateCmd inv in Invariants) { - if (inv is AssumeCmd) { - stream.Write(level + 1, "free invariant "); - } else { - stream.Write(level + 1, "invariant "); - } - Cmd.EmitAttributes(stream, inv.Attributes); - inv.Expr.Emit(stream); - stream.WriteLine(";"); - } - - stream.WriteLine(level, "{"); - Body.Emit(stream, level + 1); - stream.WriteLine(level, "}"); - } - } - - public class BreakCmd : StructuredCmd { - public string Label; - public BigBlock BreakEnclosure; - - public BreakCmd(IToken tok, string label) - : base(tok) { - Contract.Requires(tok != null); - this.Label = label; - } - - public override void Emit(TokenTextWriter stream, int level) { - - if (Label == null) { - stream.WriteLine(level, "break;"); - } else { - stream.WriteLine(level, "break {0};", Label); - } - } - } - - //--------------------------------------------------------------------- - // Block - public sealed class Block : Absy { - private string/*!*/ label; // Note, Label is mostly readonly, but it can change to the name of a nearby block during block coalescing and empty-block removal - - public string/*!*/ Label - { - get - { - Contract.Ensures(Contract.Result() != null); - return this.label; - } - set - { - Contract.Requires(value != null); - this.label = value; - } - } - - [Rep] - [ElementsPeer] - public List/*!*/ cmds; - - public List/*!*/ Cmds - { - get - { - Contract.Ensures(Contract.Result>() != null); - return this.cmds; - } - set - { - Contract.Requires(value != null); - this.cmds = value; - } - } - - [Rep] //PM: needed to verify Traverse.Visit - public TransferCmd TransferCmd; // maybe null only because we allow deferred initialization (necessary for cyclic structures) - - public byte[] Checksum; - - // Abstract interpretation - - // public bool currentlyTraversed; - - public enum VisitState { - ToVisit, - BeingVisited, - AlreadyVisited - }; // used by WidenPoints.Compute - public VisitState TraversingStatus; - - public int aiId; // block ID used by the abstract interpreter, which may change these numbers with each AI run - public bool widenBlock; - public int iterations; // Count the number of time we visited the block during fixpoint computation. Used to decide if we widen or not - - // VC generation and SCC computation - public List/*!*/ Predecessors; - - // This field is used during passification to null-out entries in block2Incartion hashtable early - public int succCount; - - private HashSet _liveVarsBefore; - - public IEnumerable liveVarsBefore - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); - if (this._liveVarsBefore == null) - return null; - else - return this._liveVarsBefore.AsEnumerable(); - } - set - { - Contract.Requires(cce.NonNullElements(value, true)); - if (value == null) - this._liveVarsBefore = null; - else - this._liveVarsBefore = new HashSet(value); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.label != null); - Contract.Invariant(this.cmds != null); - Contract.Invariant(cce.NonNullElements(this._liveVarsBefore, true)); - } - - public bool IsLive(Variable v) { - Contract.Requires(v != null); - if (liveVarsBefore == null) - return true; - return liveVarsBefore.Contains(v); - } - - public Block() - : this(Token.NoToken, "", new List(), new ReturnCmd(Token.NoToken)) { - - } - - public Block(IToken tok, string/*!*/ label, List/*!*/ cmds, TransferCmd transferCmd) - : base(tok) { - Contract.Requires(label != null); - Contract.Requires(cmds != null); - Contract.Requires(tok != null); - this.label = label; - this.cmds = cmds; - this.TransferCmd = transferCmd; - this.Predecessors = new List(); - this._liveVarsBefore = null; - this.TraversingStatus = VisitState.ToVisit; - this.iterations = 0; - } - - public void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - stream.WriteLine(); - stream.WriteLine( - this, - level, - "{0}:{1}", - CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.Label) : this.Label, - this.widenBlock ? " // cut point" : ""); - - foreach (Cmd/*!*/ c in this.Cmds) { - Contract.Assert(c != null); - c.Emit(stream, level + 1); - } - Contract.Assume(this.TransferCmd != null); - this.TransferCmd.Emit(stream, level + 1); - } - - public void Register(ResolutionContext rc) { - Contract.Requires(rc != null); - rc.AddBlock(this); - } - - public override void Resolve(ResolutionContext rc) { - - - foreach (Cmd/*!*/ c in Cmds) { - Contract.Assert(c != null); - c.Resolve(rc); - } - Contract.Assume(this.TransferCmd != null); - TransferCmd.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - - foreach (Cmd/*!*/ c in Cmds) { - Contract.Assert(c != null); - c.Typecheck(tc); - } - Contract.Assume(this.TransferCmd != null); - TransferCmd.Typecheck(tc); - } - - /// - /// Reset the abstract intepretation state of this block. It does this by putting the iterations to 0 and the pre and post states to null - /// - public void ResetAbstractInterpretationState() { - // this.currentlyTraversed = false; - this.TraversingStatus = VisitState.ToVisit; - this.iterations = 0; - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return this.Label + (this.widenBlock ? "[w]" : ""); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBlock(this); - } - } - - //--------------------------------------------------------------------- - // Commands - [ContractClassFor(typeof(Cmd))] - public abstract class CmdContracts : Cmd { - public CmdContracts() :base(null){ - - } - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - public override void AddAssignedVariables(List vars) { - Contract.Requires(vars != null); - throw new NotImplementedException(); - } - } - - public static class ChecksumHelper - { - public static void ComputeChecksums(Cmd cmd, Implementation impl, ISet usedVariables, byte[] currentChecksum = null) - { - if (CommandLineOptions.Clo.VerifySnapshots < 2) - { - return; - } - - if (cmd.IrrelevantForChecksumComputation) - { - cmd.Checksum = currentChecksum; - return; - } - - var assumeCmd = cmd as AssumeCmd; - if (assumeCmd != null - && QKeyValue.FindBoolAttribute(assumeCmd.Attributes, "assumption_variable_initialization")) - { - // Ignore assumption variable initializations. - assumeCmd.Checksum = currentChecksum; - return; - } - - using (var strWr = new System.IO.StringWriter()) - using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) - { - tokTxtWr.UseForComputingChecksums = true; - var havocCmd = cmd as HavocCmd; - if (havocCmd != null) - { - tokTxtWr.Write("havoc "); - var relevantVars = havocCmd.Vars.Where(e => usedVariables.Contains(e.Decl) && !e.Decl.Name.StartsWith("a##cached##")).OrderBy(e => e.Name).ToList(); - relevantVars.Emit(tokTxtWr, true); - tokTxtWr.WriteLine(";"); - } - else - { - cmd.Emit(tokTxtWr, 0); - } - var md5 = System.Security.Cryptography.MD5.Create(); - var str = strWr.ToString(); - if (str.Any()) - { - var data = System.Text.Encoding.UTF8.GetBytes(str); - var checksum = md5.ComputeHash(data); - currentChecksum = currentChecksum != null ? CombineChecksums(currentChecksum, checksum) : checksum; - } - cmd.Checksum = currentChecksum; - } - - var assertCmd = cmd as AssertCmd; - if (assertCmd != null && assertCmd.Checksum != null) - { - var assertRequiresCmd = assertCmd as AssertRequiresCmd; - if (assertRequiresCmd != null) - { - impl.AddAssertionChecksum(assertRequiresCmd.Checksum); - impl.AddAssertionChecksum(assertRequiresCmd.Call.Checksum); - assertRequiresCmd.SugaredCmdChecksum = assertRequiresCmd.Call.Checksum; - } - else - { - impl.AddAssertionChecksum(assertCmd.Checksum); - } - } - - var sugaredCmd = cmd as SugaredCmd; - if (sugaredCmd != null) - { - // The checksum of a sugared command should not depend on the desugaring itself. - var stateCmd = sugaredCmd.Desugaring as StateCmd; - if (stateCmd != null) - { - foreach (var c in stateCmd.Cmds) - { - ComputeChecksums(c, impl, usedVariables, currentChecksum); - currentChecksum = c.Checksum; - if (c.SugaredCmdChecksum == null) - { - c.SugaredCmdChecksum = cmd.Checksum; - } - } - } - else - { - ComputeChecksums(sugaredCmd.Desugaring, impl, usedVariables, currentChecksum); - } - } - } - - public static byte[] CombineChecksums(byte[] first, byte[] second, bool unordered = false) - { - Contract.Requires(first != null && (second == null || first.Length == second.Length)); - - var result = (byte[])(first.Clone()); - for (int i = 0; second != null && i < second.Length; i++) - { - if (unordered) - { - result[i] += second[i]; - } - else - { - result[i] = (byte)(result[i] * 31 ^ second[i]); - } - } - return result; - } - } - - [ContractClass(typeof(CmdContracts))] - public abstract class Cmd : Absy { - public byte[] Checksum { get; internal set; } - public byte[] SugaredCmdChecksum { get; internal set; } - public bool IrrelevantForChecksumComputation { get; set; } - - public Cmd(IToken/*!*/ tok) - : base(tok) { - Contract.Assert(tok != null); - } - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - public abstract void AddAssignedVariables(List/*!*/ vars); - public void CheckAssignments(TypecheckingContext tc) - { - Contract.Requires(tc != null); - List/*!*/ vars = new List(); - this.AddAssignedVariables(vars); - foreach (Variable/*!*/ v in vars) - { - Contract.Assert(v != null); - if (!v.IsMutable) - { - tc.Error(this, "command assigns to an immutable variable: {0}", v.Name); - } - else if (!CommandLineOptions.Clo.DoModSetAnalysis && v is GlobalVariable) - { - if (tc.Yields) { - // a yielding procedure is allowed to modify any global variable - } - else if (tc.Frame == null) - { - tc.Error(this, "update to a global variable allowed only inside an atomic action of a yielding procedure"); - } - else if (!tc.InFrame(v)) - { - tc.Error(this, "command assigns to a global variable that is not in the enclosing procedure's modifies clause: {0}", v.Name); - } - } - } - } - - // Methods to simulate the old SimpleAssignCmd and MapAssignCmd - public static AssignCmd SimpleAssign(IToken tok, IdentifierExpr lhs, Expr rhs) { - Contract.Requires(rhs != null); - Contract.Requires(lhs != null); - Contract.Requires(tok != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ lhss = new List(); - List/*!*/ rhss = new List(); - - lhss.Add(new SimpleAssignLhs(lhs.tok, lhs)); - rhss.Add(rhs); - - return new AssignCmd(tok, lhss, rhss); - } - - public static AssignCmd/*!*/ MapAssign(IToken tok, - IdentifierExpr/*!*/ map, - List/*!*/ indexes, Expr/*!*/ rhs) { - - Contract.Requires(tok != null); - Contract.Requires(map != null); - Contract.Requires(indexes != null); - Contract.Requires(rhs != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ lhss = new List(); - List/*!*/ rhss = new List(); - List/*!*/ indexesList = new List(); - - - - foreach (Expr e in indexes) - indexesList.Add(cce.NonNull(e)); - - lhss.Add(new MapAssignLhs(map.tok, - new SimpleAssignLhs(map.tok, map), - indexesList)); - rhss.Add(rhs); - - return new AssignCmd(tok, lhss, rhss); - } - - public static AssignCmd/*!*/ MapAssign(IToken tok, - IdentifierExpr/*!*/ map, - params Expr[]/*!*/ args) { - Contract.Requires(tok != null); - Contract.Requires(map != null); - Contract.Requires(args != null); - Contract.Requires(args.Length > 0); // at least the rhs - Contract.Requires(Contract.ForAll(args, i => i != null)); - Contract.Ensures(Contract.Result() != null); - - List/*!*/ lhss = new List(); - List/*!*/ rhss = new List(); - List/*!*/ indexesList = new List(); - - for (int i = 0; i < args.Length - 1; ++i) - indexesList.Add(cce.NonNull(args[i])); - - lhss.Add(new MapAssignLhs(map.tok, - new SimpleAssignLhs(map.tok, map), - indexesList)); - rhss.Add(cce.NonNull(args[args.Length - 1])); - - return new AssignCmd(tok, lhss, rhss); - } - - /// - /// This is a helper routine for printing a linked list of attributes. Each attribute - /// is terminated by a space. - /// - public static void EmitAttributes(TokenTextWriter stream, QKeyValue attributes) { - Contract.Requires(stream != null); - - if (stream.UseForComputingChecksums) { return; } - - for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { - kv.Emit(stream); - stream.Write(" "); - } - } - public static void ResolveAttributes(QKeyValue attributes, ResolutionContext rc) { - Contract.Requires(rc != null); - for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { - kv.Resolve(rc); - } - } - public static void TypecheckAttributes(QKeyValue attributes, TypecheckingContext tc) { - Contract.Requires(tc != null); - for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { - kv.Typecheck(tc); - } - } - - [Pure] - public override string ToString() - { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { - this.Emit(stream, 0); - } - return buffer.ToString(); - } - } - - public class YieldCmd : Cmd - { - public YieldCmd(IToken/*!*/ tok) - : base(tok) - { - Contract.Requires(tok != null); - } - public override void Emit(TokenTextWriter stream, int level) - { - //Contract.Requires(stream != null); - stream.WriteLine(this, level, "yield;"); - } - public override void Resolve(ResolutionContext rc) - { - // nothing to resolve - } - public override void Typecheck(TypecheckingContext tc) - { - if (!CommandLineOptions.Clo.DoModSetAnalysis && !tc.Yields) - { - tc.Error(this, "enclosing procedure of a yield command must yield"); - } - } - public override void AddAssignedVariables(List vars) - { - // nothing to add - } - public override Absy StdDispatch(StandardVisitor visitor) - { - Contract.Ensures(Contract.Result() != null); - return visitor.VisitYieldCmd(this); - } - } - - public class CommentCmd : Cmd // just a convenience for debugging - { - public readonly string/*!*/ Comment; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Comment != null); - } - - public CommentCmd(string c) - : base(Token.NoToken) { - Contract.Requires(c != null); - Comment = c; - } - public override void Emit(TokenTextWriter stream, int level) { - if (stream.UseForComputingChecksums) { return; } - - if (this.Comment.Contains("\n")) { - stream.WriteLine(this, level, "/* {0} */", this.Comment); - } else { - stream.WriteLine(this, level, "// {0}", this.Comment); - } - } - public override void Resolve(ResolutionContext rc) { - - } - public override void AddAssignedVariables(List vars) { - - } - public override void Typecheck(TypecheckingContext tc) { - - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - - return visitor.VisitCommentCmd(this); - } - } - - // class for parallel assignments, which subsumes both the old - // SimpleAssignCmd and the old MapAssignCmd - public class AssignCmd : Cmd { - private List/*!*/ _lhss; - - public IList/*!*/ Lhss { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._lhss.AsReadOnly(); - } - set { - Contract.Requires(cce.NonNullElements(value)); - this._lhss = new List(value); - } - } - - internal void SetLhs(int index, AssignLhs lhs) - { - Contract.Requires(0 <= index && index < this.Lhss.Count); - Contract.Requires(lhs != null); - Contract.Ensures(this.Lhss[index] == lhs); - this._lhss[index] = lhs; - } - - private List/*!*/ _rhss; - - public IList/*!*/ Rhss { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._rhss.AsReadOnly(); - } - set { - Contract.Requires(cce.NonNullElements(value)); - this._rhss = new List(value); - } - } - - internal void SetRhs(int index, Expr rhs) - { - Contract.Requires(0 <= index && index < this.Rhss.Count); - Contract.Requires(rhs != null); - Contract.Ensures(this.Rhss[index] == rhs); - this._rhss[index] = rhs; - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(this._lhss)); - Contract.Invariant(cce.NonNullElements(this._rhss)); - } - - - public AssignCmd(IToken tok, IList/*!*/ lhss, IList/*!*/ rhss) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(cce.NonNullElements(rhss)); - Contract.Requires(cce.NonNullElements(lhss)); - this._lhss = new List(lhss); - this._rhss = new List(rhss); - } - - public override void Emit(TokenTextWriter stream, int level) { - stream.Write(this, level, ""); - - string/*!*/ sep = ""; - foreach (AssignLhs/*!*/ l in Lhss) { - Contract.Assert(l != null); - stream.Write(sep); - sep = ", "; - l.Emit(stream); - } - - stream.Write(" := "); - - sep = ""; - foreach (Expr/*!*/ e in Rhss) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - } - - stream.WriteLine(";"); - } - - public override void Resolve(ResolutionContext rc) { - - if (Lhss.Count != Rhss.Count) - rc.Error(this, - "number of left-hand sides does not match number of right-hand sides"); - - foreach (AssignLhs/*!*/ e in Lhss) { - Contract.Assert(e != null); - e.Resolve(rc); - } - foreach (Expr/*!*/ e in Rhss) { - Contract.Assert(e != null); - e.Resolve(rc); - } - - // check for double occurrences of assigned variables - // (could be optimised) - for (int i = 0; i < Lhss.Count; ++i) { - for (int j = i + 1; j < Lhss.Count; ++j) { - if (cce.NonNull(Lhss[i].DeepAssignedVariable).Equals( - Lhss[j].DeepAssignedVariable)) - rc.Error(Lhss[j], - "variable {0} is assigned more than once in parallel assignment", - Lhss[j].DeepAssignedVariable); - } - } - - for (int i = 0; i < Lhss.Count; i++) - { - var lhs = Lhss[i].AsExpr as IdentifierExpr; - if (lhs != null && lhs.Decl != null && QKeyValue.FindBoolAttribute(lhs.Decl.Attributes, "assumption")) - { - var rhs = Rhss[i] as NAryExpr; - if (rhs == null - || !(rhs.Fun is BinaryOperator) - || ((BinaryOperator)(rhs.Fun)).Op != BinaryOperator.Opcode.And - || !(rhs.Args[0] is IdentifierExpr) - || ((IdentifierExpr)(rhs.Args[0])).Name != lhs.Name) - { - rc.Error(tok, string.Format("RHS of assignment to assumption variable {0} must match expression \"{0} && \"", lhs.Name)); - } - else if (rc.HasVariableBeenAssigned(lhs.Decl.Name)) - { - rc.Error(tok, "assumption variable may not be assigned to more than once"); - } - else - { - rc.MarkVariableAsAssigned(lhs.Decl.Name); - } - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - - foreach (AssignLhs/*!*/ e in Lhss) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - foreach (Expr/*!*/ e in Rhss) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - - this.CheckAssignments(tc); - - for (int i = 0; i < Lhss.Count; ++i) { - Type ltype = Lhss[i].Type; - Type rtype = Rhss[i].Type; - if (ltype != null && rtype != null) { - // otherwise, there has already been an error when - // typechecking the lhs or rhs - if (!ltype.Unify(rtype)) - tc.Error(Lhss[i], - "mismatched types in assignment command (cannot assign {0} to {1})", - rtype, ltype); - } - } - } - - public override void AddAssignedVariables(List vars) { - - foreach (AssignLhs/*!*/ l in Lhss) { - Contract.Assert(l != null); - vars.Add(l.DeepAssignedVariable); - } - } - - // transform away the syntactic sugar of map assignments and - // determine an equivalent assignment in which all rhs are simple - // variables - public AssignCmd/*!*/ AsSimpleAssignCmd { - get { - Contract.Ensures(Contract.Result() != null); - - List/*!*/ newLhss = new List(); - List/*!*/ newRhss = new List(); - - for (int i = 0; i < Lhss.Count; ++i) { - IdentifierExpr/*!*/ newLhs; - Expr/*!*/ newRhs; - Lhss[i].AsSimpleAssignment(Rhss[i], out newLhs, out newRhs); - newLhss.Add(new SimpleAssignLhs(Token.NoToken, newLhs)); - newRhss.Add(newRhs); - } - - return new AssignCmd(Token.NoToken, newLhss, newRhss); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - - return visitor.VisitAssignCmd(this); - } - } - - // There are two different kinds of left-hand sides in assignments: - // simple variables (identifiers), or locations of a map - [ContractClass(typeof(AssignLhsContracts))] - public abstract class AssignLhs : Absy { - // The type of the lhs is determined during typechecking - public abstract Type Type { - get; - } - // Determine the variable that is actually assigned in this lhs - public abstract IdentifierExpr/*!*/ DeepAssignedIdentifier { - get; - } - public abstract Variable DeepAssignedVariable { - get; - } - - public AssignLhs(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - public abstract void Emit(TokenTextWriter/*!*/ stream); - - public abstract Expr/*!*/ AsExpr { - get; - } - - // transform away the syntactic sugar of map assignments and - // determine an equivalent simple assignment - internal abstract void AsSimpleAssignment(Expr/*!*/ rhs, - out IdentifierExpr/*!*/ simpleLhs, - out Expr/*!*/ simpleRhs); - } - [ContractClassFor(typeof(AssignLhs))] - public abstract class AssignLhsContracts : AssignLhs { - public AssignLhsContracts():base(null) - { - - }public override IdentifierExpr DeepAssignedIdentifier { - - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - public override Expr AsExpr { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - } - internal override void AsSimpleAssignment(Expr rhs, out IdentifierExpr simpleLhs, out Expr simpleRhs) { - Contract.Requires(rhs != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); - - throw new NotImplementedException(); - } - } - - public class SimpleAssignLhs : AssignLhs { - public IdentifierExpr/*!*/ AssignedVariable; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(AssignedVariable != null); - } - - - public override Type Type { - get { - return AssignedVariable.Type; - } - } - - public override IdentifierExpr/*!*/ DeepAssignedIdentifier { - get { - Contract.Ensures(Contract.Result() != null); - return AssignedVariable; - } - } - - public override Variable DeepAssignedVariable { - get { - return AssignedVariable.Decl; - } - } - - public SimpleAssignLhs(IToken tok, IdentifierExpr assignedVariable) - : base(tok) { - Contract.Requires(assignedVariable != null); - Contract.Requires(tok != null); - AssignedVariable = assignedVariable; - } - public override void Resolve(ResolutionContext rc) { - - AssignedVariable.Resolve(rc); - } - public override void Typecheck(TypecheckingContext tc) { - - AssignedVariable.Typecheck(tc); - } - public override void Emit(TokenTextWriter stream) { - - AssignedVariable.Emit(stream); - } - public override Expr/*!*/ AsExpr { - get { - Contract.Ensures(Contract.Result() != null); - - return AssignedVariable; - } - } - internal override void AsSimpleAssignment(Expr rhs, - out IdentifierExpr/*!*/ simpleLhs, - out Expr/*!*/ simpleRhs) { - - - - simpleLhs = AssignedVariable; - simpleRhs = rhs; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - - - return visitor.VisitSimpleAssignLhs(this); - } - } - - // A map-assignment-lhs (m[t1, t2, ...] := ...) is quite similar to - // a map select expression, but it is cleaner to keep those two - // things separate - public class MapAssignLhs : AssignLhs { - public AssignLhs/*!*/ Map; - - public List/*!*/ Indexes; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Map != null); - Contract.Invariant(cce.NonNullElements(Indexes)); - } - - - // The instantiation of type parameters of the map that is - // determined during type checking. - public TypeParamInstantiation TypeParameters = null; - - private Type TypeAttr = null; - - public override Type Type { - get { - return TypeAttr; - } - } - - public override IdentifierExpr/*!*/ DeepAssignedIdentifier { - get { - Contract.Ensures(Contract.Result() != null); - - return Map.DeepAssignedIdentifier; - } - } - - public override Variable DeepAssignedVariable { - get { - return Map.DeepAssignedVariable; - } - } - - public MapAssignLhs(IToken tok, AssignLhs map, List/*!*/ indexes) - : base(tok) { - Contract.Requires(map != null); - Contract.Requires(tok != null); - Contract.Requires(cce.NonNullElements(indexes)); - - Map = map; - Indexes = indexes; - } - public override void Resolve(ResolutionContext rc) { - - Map.Resolve(rc); - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - e.Resolve(rc); - } - } - public override void Typecheck(TypecheckingContext tc) { - - Map.Typecheck(tc); - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - - // we use the same typechecking code as in MapSelect - List/*!*/ selectArgs = new List(); - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - selectArgs.Add(e); - } - TypeParamInstantiation/*!*/ tpInsts; - TypeAttr = - MapSelect.Typecheck(cce.NonNull(Map.Type), Map, - selectArgs, out tpInsts, tc, tok, "map assignment"); - TypeParameters = tpInsts; - } - public override void Emit(TokenTextWriter stream) { - - Map.Emit(stream); - stream.Write("["); - string/*!*/ sep = ""; - foreach (Expr/*!*/ e in Indexes) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - } - stream.Write("]"); - } - public override Expr/*!*/ AsExpr { - get { - Contract.Ensures(Contract.Result() != null); - - NAryExpr/*!*/ res = Expr.Select(Map.AsExpr, Indexes); - Contract.Assert(res != null); - res.TypeParameters = this.TypeParameters; - res.Type = this.Type; - return res; - } - } - internal override void AsSimpleAssignment(Expr rhs, - out IdentifierExpr/*!*/ simpleLhs, - out Expr/*!*/ simpleRhs) { //Contract.Requires(rhs != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); - Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); - - NAryExpr/*!*/ newRhs = Expr.Store(Map.AsExpr, Indexes, rhs); - Contract.Assert(newRhs != null); - newRhs.TypeParameters = this.TypeParameters; - newRhs.Type = Map.Type; - Map.AsSimpleAssignment(newRhs, out simpleLhs, out simpleRhs); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitMapAssignLhs(this); - } - } - - /// - /// A StateCmd is like an imperative-let binding around a sequence of commands. - /// There is no user syntax for a StateCmd. Instead, a StateCmd is only used - /// temporarily during the desugaring phase inside the VC generator. - /// - public class StateCmd : Cmd { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._locals != null); - Contract.Invariant(this._cmds != null); - } - - private List _locals; - - public /*readonly, except for the StandardVisitor*/ List/*!*/ Locals { - get { - Contract.Ensures(Contract.Result>() != null); - return this._locals; - } - internal set { - Contract.Requires(value != null); - this._locals = value; - } - } - - private List _cmds; - - public /*readonly, except for the StandardVisitor*/ List/*!*/ Cmds { - get { - Contract.Ensures(Contract.Result>() != null); - return this._cmds; - } - set { - Contract.Requires(value != null); - this._cmds = value; - } - } - - public StateCmd(IToken tok, List/*!*/ locals, List/*!*/ cmds) - : base(tok) { - Contract.Requires(locals != null); - Contract.Requires(cmds != null); - Contract.Requires(tok != null); - this._locals = locals; - this._cmds = cmds; - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.PushVarContext(); - foreach (Variable/*!*/ v in Locals) { - Contract.Assert(v != null); - rc.AddVariable(v, false); - } - foreach (Cmd/*!*/ cmd in Cmds) { - Contract.Assert(cmd != null); - cmd.Resolve(rc); - } - rc.PopVarContext(); - } - - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - List/*!*/ vs = new List(); - foreach (Cmd/*!*/ cmd in this.Cmds) { - Contract.Assert(cmd != null); - cmd.AddAssignedVariables(vs); - } - System.Collections.Hashtable/*!*/ localsSet = new System.Collections.Hashtable(); - foreach (Variable/*!*/ local in this.Locals) { - Contract.Assert(local != null); - localsSet[local] = bool.TrueString; - } - foreach (Variable/*!*/ v in vs) { - Contract.Assert(v != null); - if (!localsSet.ContainsKey(v)) { - vars.Add(v); - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (Cmd/*!*/ cmd in Cmds) { - Contract.Assert(cmd != null); - cmd.Typecheck(tc); - } - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(this, level, "{"); - foreach (Variable/*!*/ v in Locals) { - Contract.Assert(v != null); - v.Emit(stream, level + 1); - } - foreach (Cmd/*!*/ c in Cmds) { - Contract.Assert(c != null); - c.Emit(stream, level + 1); - } - stream.WriteLine(level, "}"); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitStateCmd(this); - } - } - [ContractClass(typeof(SugaredCmdContracts))] - abstract public class SugaredCmd : Cmd { - private Cmd desugaring; // null until desugared - - public SugaredCmd(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - - public Cmd/*!*/ Desugaring { - get { - Contract.Ensures(Contract.Result() != null); - - if (desugaring == null) { - desugaring = ComputeDesugaring(); - } - return desugaring; - } - } - /// - /// This method invokes "visitor.Visit" on the desugaring, and then updates the - /// desugaring to the result thereof. The method's intended use is for subclasses - /// of StandardVisitor that need to also visit the desugaring. Note, since the - /// "desugaring" field is updated, this is not an appropriate method to be called - /// be a ReadOnlyVisitor; such visitors should instead just call - /// visitor.Visit(sugaredCmd.Desugaring). - /// - public void VisitDesugaring(StandardVisitor visitor) { - Contract.Requires(visitor != null && !(visitor is ReadOnlyVisitor)); - if (desugaring != null) { - desugaring = (Cmd)visitor.Visit(desugaring); - } - } - protected abstract Cmd/*!*/ ComputeDesugaring(); - - public void ExtendDesugaring(IEnumerable before, IEnumerable beforePreconditionCheck, IEnumerable after) - { - var desug = Desugaring; - var stCmd = desug as StateCmd; - if (stCmd != null) - { - stCmd.Cmds.InsertRange(0, before); - var idx = stCmd.Cmds.FindIndex(c => c is AssertCmd || c is HavocCmd || c is AssumeCmd); - if (idx < 0) - { - idx = 0; - } - stCmd.Cmds.InsertRange(idx, beforePreconditionCheck); - stCmd.Cmds.AddRange(after); - } - else if (desug != null) - { - var cmds = new List(before); - cmds.Add(desug); - cmds.AddRange(after); - desugaring = new StateCmd(Token.NoToken, new List(), cmds); - } - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - if (CommandLineOptions.Clo.PrintDesugarings && !stream.UseForComputingChecksums) { - stream.WriteLine(this, level, "/*** desugaring:"); - Desugaring.Emit(stream, level); - stream.WriteLine(level, "**** end desugaring */"); - } - } - } - [ContractClassFor(typeof(SugaredCmd))] - public abstract class SugaredCmdContracts : SugaredCmd { - public SugaredCmdContracts() :base(null){ - - } - protected override Cmd ComputeDesugaring() { - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - } - - public abstract class CallCommonality : SugaredCmd { - public QKeyValue Attributes; - - private bool isFree = false; - public bool IsFree { - get { - return isFree; - } - set { - isFree = value; - } - } - - private bool isAsync = false; - public bool IsAsync - { - get - { - return isAsync; - } - set - { - isAsync = value; - } - } - - protected CallCommonality(IToken tok, QKeyValue kv) - : base(tok) { - Contract.Requires(tok != null); - Attributes = kv; - } - - protected enum TempVarKind { - Formal, - Old, - Bound - } - - // We have to give the type explicitly, because the type of the formal "likeThisOne" can contain type variables - protected Variable CreateTemporaryVariable(List tempVars, Variable likeThisOne, Type ty, TempVarKind kind, ref int uniqueId) { - Contract.Requires(ty != null); - Contract.Requires(likeThisOne != null); - Contract.Requires(tempVars != null); - Contract.Ensures(Contract.Result() != null); - string/*!*/ tempNamePrefix; - switch (kind) { - case TempVarKind.Formal: - tempNamePrefix = "formal@"; - break; - case TempVarKind.Old: - tempNamePrefix = "old@"; - break; - case TempVarKind.Bound: - tempNamePrefix = "forall@"; - break; - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // unexpected kind - } - TypedIdent ti = likeThisOne.TypedIdent; - // KLM: uniqueId was messing up FixedPointVC for unknown reason. - // I reverted this change for FixedPointVC only. - int id = CommandLineOptions.Clo.FixedPointEngine != null ? UniqueId : (uniqueId++); - TypedIdent newTi = new TypedIdent(ti.tok, "call" + id + tempNamePrefix + ti.Name, ty); - Variable/*!*/ v; - if (kind == TempVarKind.Bound) { - v = new BoundVariable(likeThisOne.tok, newTi); - } else { - v = new LocalVariable(likeThisOne.tok, newTi); - tempVars.Add(v); - } - return v; - } - } - - public class ParCallCmd : CallCommonality, IPotentialErrorNode - { - public List CallCmds; - public ParCallCmd(IToken tok, List callCmds) - : base(tok, null) - { - this.CallCmds = callCmds; - } - public ParCallCmd(IToken tok, List callCmds, QKeyValue kv) - : base(tok, kv) - { - this.CallCmds = callCmds; - } - protected override Cmd ComputeDesugaring() - { - throw new NotImplementedException(); - } - private object errorData; - public object ErrorData - { - get - { - return errorData; - } - set - { - errorData = value; - } - } - public override void Resolve(ResolutionContext rc) - { - ResolveAttributes(Attributes, rc); - foreach (CallCmd callCmd in CallCmds) - { - callCmd.Resolve(rc); - } - HashSet parallelCallLhss = new HashSet(); - foreach (CallCmd callCmd in CallCmds) - { - foreach (IdentifierExpr ie in callCmd.Outs) - { - if (parallelCallLhss.Contains(ie.Decl)) - { - rc.Error(this, "left-hand side of parallel call command contains variable twice: {0}", ie.Name); - } - else - { - parallelCallLhss.Add(ie.Decl); - } - } - } - } - public override void Typecheck(TypecheckingContext tc) - { - TypecheckAttributes(Attributes, tc); - if (!CommandLineOptions.Clo.DoModSetAnalysis) - { - if (!tc.Yields) - { - tc.Error(this, "enclosing procedure of a parallel call must yield"); - } - foreach (CallCmd callCmd in CallCmds) - { - if (!QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "yields")) - { - tc.Error(callCmd, "target procedure of a parallel call must yield"); - } - } - } - foreach (CallCmd callCmd in CallCmds) - { - callCmd.Typecheck(tc); - } - } - public override void AddAssignedVariables(List vars) - { - foreach (CallCmd callCmd in CallCmds) - { - callCmd.AddAssignedVariables(vars); - } - } - public override Absy StdDispatch(StandardVisitor visitor) - { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitParCallCmd(this); - } - } - - public class CallCmd : CallCommonality, IPotentialErrorNode - { - public string/*!*/ callee { get; set; } - public Procedure Proc; - public LocalVariable AssignedAssumptionVariable; - - // Element of the following lists can be null, which means that - // the call happens with * as these parameters - public List/*!*/ Ins; - public List/*!*/ Outs; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(callee != null); - Contract.Invariant(Ins != null); - Contract.Invariant(Outs != null); - } - - //public Lattice.Element StateAfterCall; - - // The instantiation of type parameters that is determined during - // type checking - public TypeParamInstantiation TypeParameters = null; - - // TODO: convert to use generics - private object errorData; - public object ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - public CallCmd(IToken tok, string callee, List ins, List outs) - : base(tok, null) { - Contract.Requires(outs != null); - Contract.Requires(ins != null); - Contract.Requires(callee != null); - Contract.Requires(tok != null); - this.callee = callee; - this.Ins = ins; - this.Outs = outs; - } - public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv) - : base(tok, kv) { - Contract.Requires(outs != null); - Contract.Requires(ins != null); - Contract.Requires(callee != null); - Contract.Requires(tok != null); - this.callee = callee; - this.Ins = ins; - this.Outs = outs; - } - - public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv, bool IsAsync) - : base(tok, kv) - { - Contract.Requires(outs != null); - Contract.Requires(ins != null); - Contract.Requires(callee != null); - Contract.Requires(tok != null); - this.callee = callee; - this.Ins = ins; - this.Outs = outs; - this.IsAsync = IsAsync; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, ""); - if (IsFree) { - stream.Write("free "); - } - if (IsAsync) { - stream.Write("async "); - } - stream.Write("call "); - EmitAttributes(stream, Attributes); - string sep = ""; - if (Outs.Count > 0) { - foreach (Expr arg in Outs) { - stream.Write(sep); - sep = ", "; - if (arg == null) { - stream.Write("*"); - } else { - arg.Emit(stream); - } - } - stream.Write(" := "); - } - stream.Write(TokenTextWriter.SanitizeIdentifier(callee)); - stream.Write("("); - sep = ""; - foreach (Expr arg in Ins) { - stream.Write(sep); - sep = ", "; - if (arg == null) { - stream.Write("*"); - } else { - arg.Emit(stream); - } - } - stream.WriteLine(");"); - base.Emit(stream, level); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (Proc != null) { - // already resolved - return; - } - ResolveAttributes(Attributes, rc); - Proc = rc.LookUpProcedure(callee) as Procedure; - if (Proc == null) { - rc.Error(this, "call to undeclared procedure: {0}", callee); - } - foreach (Expr e in Ins) { - if (e != null) { - e.Resolve(rc); - } - } - HashSet actualOuts = new HashSet(); - foreach (IdentifierExpr ide in Outs) { - if (ide != null) { - ide.Resolve(rc); - if (ide.Decl != null) { - if (actualOuts.Contains(ide.Decl)) { - rc.Error(this, "left-hand side of call command contains variable twice: {0}", ide.Name); - } else { - actualOuts.Add(ide.Decl); - } - } - } - } - - if (Proc == null) - return; - - // first make sure that the right number of parameters is given - // (a similar check is in CheckArgumentTypes, but we are not - // able to call this method because it cannot cope with Ins/Outs - // that are null) - if (Ins.Count != Proc.InParams.Count) { - rc.Error(this.tok, - "wrong number of arguments in call to {0}: {1}", - callee, Ins.Count); - return; - } - if (Outs.Count != Proc.OutParams.Count) { - rc.Error(this.tok, - "wrong number of result variables in call to {0}: {1}", - callee, Outs.Count); - return; - } - if (IsAsync) { - if (Proc.OutParams.Count > 0) { - rc.Error(this.tok, "a procedure called asynchronously can have no output parameters"); - return; - } - } - - // Check that type parameters can be determined using the given - // actual i/o arguments. This is done already during resolution - // because CheckBoundVariableOccurrences needs a resolution - // context - List/*!*/ formalInTypes = new List(); - List/*!*/ formalOutTypes = new List(); - for (int i = 0; i < Ins.Count; ++i) - if (Ins[i] != null) - formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); - for (int i = 0; i < Outs.Count; ++i) - if (Outs[i] != null) - formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); - - // we need to bind the type parameters for this - // (this is expected by CheckBoundVariableOccurrences) - int previousTypeBinderState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in Proc.TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - Type.CheckBoundVariableOccurrences(Proc.TypeParameters, - formalInTypes, formalOutTypes, - this.tok, "types of given arguments", - rc); - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - } - - public override void AddAssignedVariables(List vars) { - if (this.IsAsync) - return; - foreach (IdentifierExpr e in Outs) { - if (e != null) { - vars.Add(e.Decl); - } - } - Contract.Assume(this.Proc != null); - foreach (IdentifierExpr/*!*/ e in this.Proc.Modifies) { - Contract.Assert(e != null); - vars.Add(e.Decl); - } - if (AssignedAssumptionVariable != null) - { - vars.Add(AssignedAssumptionVariable); - } - } - - public override void Typecheck(TypecheckingContext tc) - { - //Contract.Requires(tc != null); - Contract.Assume(this.Proc != null); // we assume the CallCmd has been successfully resolved before calling this Typecheck method - - TypecheckAttributes(Attributes, tc); - - // typecheck in-parameters - foreach (Expr e in Ins) - if (e != null) - e.Typecheck(tc); - foreach (Expr e in Outs) - if (e != null) - e.Typecheck(tc); - this.CheckAssignments(tc); - - List/*!*/ formalInTypes = new List(); - List/*!*/ formalOutTypes = new List(); - List/*!*/ actualIns = new List(); - List/*!*/ actualOuts = new List(); - for (int i = 0; i < Ins.Count; ++i) - { - if (Ins[i] != null) - { - formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); - actualIns.Add(Ins[i]); - } - } - for (int i = 0; i < Outs.Count; ++i) - { - if (Outs[i] != null) - { - formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); - actualOuts.Add(Outs[i]); - } - } - - // match actuals with formals - List/*!*/ actualTypeParams; - Type.CheckArgumentTypes(Proc.TypeParameters, - out actualTypeParams, - formalInTypes, actualIns, - formalOutTypes, actualOuts, - this.tok, - "call to " + callee, - tc); - Contract.Assert(cce.NonNullElements(actualTypeParams)); - TypeParameters = SimpleTypeParamInstantiation.From(Proc.TypeParameters, - actualTypeParams); - - if (!CommandLineOptions.Clo.DoModSetAnalysis && IsAsync) - { - if (!tc.Yields) - { - tc.Error(this, "enclosing procedure of an async call must yield"); - } - if (!QKeyValue.FindBoolAttribute(Proc.Attributes, "yields")) - { - tc.Error(this, "target procedure of an async call must yield"); - } - } - } - - private IDictionary/*!*/ TypeParamSubstitution() { - Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); - Contract.Assume(TypeParameters != null); - IDictionary/*!*/ res = new Dictionary(); - foreach (TypeVariable/*!*/ v in TypeParameters.FormalTypeParams) { - Contract.Assert(v != null); - res.Add(v, TypeParameters[v]); - } - return res; - } - - protected override Cmd ComputeDesugaring() { - Contract.Ensures(Contract.Result() != null); - - int uniqueId = 0; - List newBlockBody = new List(); - Dictionary substMap = new Dictionary(); - Dictionary substMapOld = new Dictionary(); - Dictionary substMapBound = new Dictionary(); - List/*!*/ tempVars = new List(); - - // proc P(ins) returns (outs) - // requires Pre - // //modifies frame - // ensures Post - // - // call aouts := P(ains) - - // ins : formal in parameters of procedure - // frame : a list of global variables from the modifies clause - // outs : formal out parameters of procedure - // ains : actual in arguments passed to call - // aouts : actual variables assigned to from call - // cins : new variables created just for this call, one per ains - // cframe : new variables created just for this call, to keep track of OLD values - // couts : new variables created just for this call, one per aouts - // WildcardVars : new variables created just for this call, one per null in ains - - #region Create cins; each one is an incarnation of the corresponding in parameter - List/*!*/ cins = new List(); - List wildcardVars = new List(); - Contract.Assume(this.Proc != null); - for (int i = 0; i < this.Proc.InParams.Count; ++i) { - Variable/*!*/ param = cce.NonNull(this.Proc.InParams[i]); - bool isWildcard = this.Ins[i] == null; - - Type/*!*/ actualType; - if (isWildcard) - actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); - else - // during type checking, we have ensured that the type of the actual - // parameter Ins[i] is correct, so we can use it here - actualType = cce.NonNull(cce.NonNull(Ins[i]).Type); - - Variable cin = CreateTemporaryVariable(tempVars, param, actualType, - TempVarKind.Formal, ref uniqueId); - cins.Add(cin); - IdentifierExpr ie = new IdentifierExpr(cin.tok, cin); - substMap.Add(param, ie); - if (isWildcard) { - cin = CreateTemporaryVariable(tempVars, param, - actualType, TempVarKind.Bound, ref uniqueId); - wildcardVars.Add(cin); - ie = new IdentifierExpr(cin.tok, cin); - } - substMapBound.Add(param, ie); - } - #endregion - #region call aouts := P(ains) becomes: (open outlining one level to see) - #region cins := ains (or havoc cin when ain is null) - for (int i = 0, n = this.Ins.Count; i < n; i++) { - IdentifierExpr/*!*/ cin_exp = new IdentifierExpr(cce.NonNull(cins[i]).tok, cce.NonNull(cins[i])); - Contract.Assert(cin_exp != null); - if (this.Ins[i] != null) { - AssignCmd assign = Cmd.SimpleAssign(Token.NoToken, cin_exp, cce.NonNull(this.Ins[i])); - newBlockBody.Add(assign); - } else { - List/*!*/ ies = new List(); - ies.Add(cin_exp); - HavocCmd havoc = new HavocCmd(Token.NoToken, ies); - newBlockBody.Add(havoc); - } - } - #endregion - - #region assert (exists wildcardVars :: Pre[ins := cins]) - Substitution s = Substituter.SubstitutionFromHashtable(substMapBound); - bool hasWildcard = (wildcardVars.Count != 0); - Expr preConjunction = null; - for (int i = 0; i < this.Proc.Requires.Count; i++) { - Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); - if (!req.Free && !IsFree) { - if (hasWildcard) { - Expr pre = Substituter.Apply(s, req.Condition); - if (preConjunction == null) { - preConjunction = pre; - } else { - preConjunction = Expr.And(preConjunction, pre); - } - } else { - Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); - reqCopy.Condition = Substituter.Apply(s, req.Condition); - AssertCmd/*!*/ a = new AssertRequiresCmd(this, reqCopy); - Contract.Assert(a != null); - if (Attributes != null) - { - // Inherit attributes of call. - var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); - attrCopy = Substituter.Apply(s, attrCopy); - a.Attributes = attrCopy; - } - a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced; - newBlockBody.Add(a); - } - } - else if (CommandLineOptions.Clo.StratifiedInlining > 0) - { - // inject free requires as assume statements at the call site - AssumeCmd/*!*/ a = new AssumeCmd(req.tok, Substituter.Apply(s, req.Condition)); - Contract.Assert(a != null); - newBlockBody.Add(a); - } - } - if (hasWildcard) { - if (preConjunction == null) { - preConjunction = Expr.True; - } - Expr/*!*/ expr = new ExistsExpr(tok, wildcardVars, preConjunction); - Contract.Assert(expr != null); - AssertCmd/*!*/ a = new AssertCmd(tok, expr); - Contract.Assert(a != null); - if (Attributes != null) - { - // Inherit attributes of call. - var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); - attrCopy = Substituter.Apply(s, attrCopy); - a.Attributes = attrCopy; - } - a.ErrorDataEnhanced = AssertCmd.GenerateBoundVarMiningStrategy(expr); - newBlockBody.Add(a); - } - #endregion - - #region assume Pre[ins := cins] with formal paramters - if (hasWildcard) { - s = Substituter.SubstitutionFromHashtable(substMap); - for (int i = 0; i < this.Proc.Requires.Count; i++) { - Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); - if (!req.Free) { - Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); - reqCopy.Condition = Substituter.Apply(s, req.Condition); - AssumeCmd/*!*/ a = new AssumeCmd(tok, reqCopy.Condition); - Contract.Assert(a != null); - newBlockBody.Add(a); - } - } - } - #endregion - - #region cframe := frame (to hold onto frame values in case they are referred to in the postcondition) - List havocVarExprs = new List(); - - foreach (IdentifierExpr/*!*/ f in this.Proc.Modifies) { - Contract.Assert(f != null); - Contract.Assume(f.Decl != null); - Contract.Assert(f.Type != null); - Variable v = CreateTemporaryVariable(tempVars, f.Decl, f.Type, TempVarKind.Old, ref uniqueId); - IdentifierExpr v_exp = new IdentifierExpr(v.tok, v); - substMapOld.Add(f.Decl, v_exp); // this assumes no duplicates in this.Proc.Modifies - AssignCmd assign = Cmd.SimpleAssign(f.tok, v_exp, f); - newBlockBody.Add(assign); - - // fra - if (!havocVarExprs.Contains(f)) - havocVarExprs.Add(f); - } - #endregion - #region Create couts - List/*!*/ couts = new List(); - for (int i = 0; i < this.Proc.OutParams.Count; ++i) { - Variable/*!*/ param = cce.NonNull(this.Proc.OutParams[i]); - bool isWildcard = this.Outs[i] == null; - - Type/*!*/ actualType; - if (isWildcard) - actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); - else - // during type checking, we have ensured that the type of the actual - // out parameter Outs[i] is correct, so we can use it here - actualType = cce.NonNull(cce.NonNull(Outs[i]).Type); - - Variable cout = CreateTemporaryVariable(tempVars, param, actualType, - TempVarKind.Formal, ref uniqueId); - couts.Add(cout); - IdentifierExpr ie = new IdentifierExpr(cout.tok, cout); - substMap.Add(param, ie); - - if (!havocVarExprs.Contains(ie)) - havocVarExprs.Add(ie); - } - // add the where clauses, now that we have the entire substitution map - foreach (Variable/*!*/ param in this.Proc.OutParams) { - Contract.Assert(param != null); - Expr w = param.TypedIdent.WhereExpr; - if (w != null) { - IdentifierExpr ie = (IdentifierExpr/*!*/)cce.NonNull(substMap[param]); - Contract.Assert(ie.Decl != null); - ie.Decl.TypedIdent.WhereExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(substMap), w); - } - } - #endregion - - #region havoc frame, couts - // pass on this's token - HavocCmd hc = new HavocCmd(this.tok, havocVarExprs); - newBlockBody.Add(hc); - #endregion - - #region assume Post[ins, outs, old(frame) := cins, couts, cframe] - calleeSubstitution = Substituter.SubstitutionFromHashtable(substMap, true, Proc); - calleeSubstitutionOld = Substituter.SubstitutionFromHashtable(substMapOld, true, Proc); - foreach (Ensures/*!*/ e in this.Proc.Ensures) { - Contract.Assert(e != null); - Expr copy = Substituter.ApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, e.Condition); - AssumeCmd assume = new AssumeCmd(this.tok, copy); - #region stratified inlining support - if (QKeyValue.FindBoolAttribute(e.Attributes, "si_fcall")) - { - assume.Attributes = Attributes; - } - if (QKeyValue.FindBoolAttribute(e.Attributes, "candidate")) - { - assume.Attributes = new QKeyValue(Token.NoToken, "candidate", new List(), assume.Attributes); - assume.Attributes.AddParam(this.callee); - } - #endregion - newBlockBody.Add(assume); - } - #endregion - - #region aouts := couts - for (int i = 0, n = this.Outs.Count; i < n; i++) { - if (this.Outs[i] != null) { - Variable/*!*/ param_i = cce.NonNull(this.Proc.OutParams[i]); - Expr/*!*/ cout_exp = new IdentifierExpr(cce.NonNull(couts[i]).tok, cce.NonNull(couts[i])); - Contract.Assert(cout_exp != null); - AssignCmd assign = Cmd.SimpleAssign(param_i.tok, cce.NonNull(this.Outs[i]), cout_exp); - newBlockBody.Add(assign); - } - } - #endregion - #endregion - - return new StateCmd(this.tok, tempVars, newBlockBody); - } - - class NameEqualityComparer : EqualityComparer - { - public override bool Equals(IdentifierExpr x, IdentifierExpr y) - { - return x.Name.Equals(y.Name); - } - - public override int GetHashCode(IdentifierExpr obj) - { - return obj.Name.GetHashCode(); - } - } - - NameEqualityComparer comparer = new NameEqualityComparer(); - - public Substitution calleeSubstitution; - public Substitution calleeSubstitutionOld; - - public IEnumerable UnmodifiedBefore(Procedure oldProcedure) - { - Contract.Requires(oldProcedure != null); - - return Proc.Modifies.Except(oldProcedure.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); - } - - public IEnumerable ModifiedBefore(Procedure oldProcedure) - { - Contract.Requires(oldProcedure != null); - - return oldProcedure.Modifies.Except(Proc.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); - } - - public Expr Postcondition(Procedure procedure, List modifies, Dictionary oldSubst, Program program, Func extract) - { - Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && modifies != null && oldSubst != null && program != null && extract != null); - - Substitution substOldCombined = v => { Expr s; if (oldSubst.TryGetValue(v, out s)) { return s; } return calleeSubstitutionOld(v); }; - - var clauses = procedure.Ensures.Select(e => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, substOldCombined, e.Condition, program)).Concat(modifies); - // TODO(wuestholz): Try extracting a function for each clause: - // return Conjunction(clauses.Select(c => extract(c))); - var conj = Expr.And(clauses, true); - return conj != null ? extract(conj) : conj; - } - - public Expr CheckedPrecondition(Procedure procedure, Program program, Func extract) - { - Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && program != null && extract != null); - - var clauses = procedure.Requires.Where(r => !r.Free).Select(r => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, r.Condition, program)); - // TODO(wuestholz): Try extracting a function for each clause: - // return Conjunction(clauses.Select(c => extract(c))); - var conj = Expr.And(clauses, true); - return conj != null ? extract(conj) : conj; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitCallCmd(this); - } - } - - public abstract class PredicateCmd : Cmd { - public QKeyValue Attributes; - public /*readonly--except in StandardVisitor*/ Expr/*!*/ Expr; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Expr != null); - } - - public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - Expr = expr; - } - public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - Expr = expr; - Attributes = kv; - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Expr.Resolve(rc); - } - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - } - } - - public abstract class MiningStrategy { - // abstract class to bind all MiningStrategys, i.e., all types of enhanced error data - // types together - } - - public class ListOfMiningStrategies : MiningStrategy { - - private List/*!*/ _msList; - - public List/*!*/ msList - { - get - { - Contract.Ensures(Contract.Result>() != null); - return this._msList; - } - set - { - Contract.Requires(value != null); - this._msList = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._msList != null); - } - - public ListOfMiningStrategies(List l) { - Contract.Requires(l != null); - this._msList = l; - } - } - - public class EEDTemplate : MiningStrategy { - private string/*!*/ _reason; - public string/*!*/ reason - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._reason; - } - set - { - Contract.Requires(value != null); - this._reason = value; - } - } - - private List/*!*/ exprList; - public IEnumerable Expressions - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return this.exprList.AsReadOnly(); - } - set - { - Contract.Requires(cce.NonNullElements(value)); - this.exprList = new List(value); - } - } - - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._reason != null); - Contract.Invariant(cce.NonNullElements(this.exprList)); - } - - public EEDTemplate(string reason, List/*!*/ exprList) { - Contract.Requires(reason != null); - Contract.Requires(cce.NonNullElements(exprList)); - this._reason = reason; - this.exprList = exprList; - } - } - - public class AssertCmd : PredicateCmd, IPotentialErrorNode - { - public Expr OrigExpr; - public Dictionary IncarnationMap; - - Expr verifiedUnder; - public Expr VerifiedUnder - { - get - { - if (verifiedUnder != null) - { - return verifiedUnder; - } - verifiedUnder = QKeyValue.FindExprAttribute(Attributes, "verified_under"); - return verifiedUnder; - } - } - - public void MarkAsVerifiedUnder(Expr expr) - { - Attributes = new QKeyValue(tok, "verified_under", new List { expr }, Attributes); - verifiedUnder = expr; - } - - // TODO: convert to use generics - private object errorData; - public object ErrorData { - get { - return errorData; - } - set { - errorData = value; - } - } - - public string ErrorMessage { - get { - return QKeyValue.FindStringAttribute(Attributes, "msg"); - } - } - - private MiningStrategy errorDataEnhanced; - public MiningStrategy ErrorDataEnhanced { - get { - return errorDataEnhanced; - } - set { - errorDataEnhanced = value; - } - } - - public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); - } - - public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) - : base(tok, expr, kv) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "assert "); - EmitAttributes(stream, Attributes); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - ResolveAttributes(Attributes, rc); - base.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - TypecheckAttributes(Attributes, tc); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "an asserted expression must be of type bool (got: {0})", Expr.Type); - } - } - - public static MiningStrategy GenerateBoundVarMiningStrategy(Expr expr) { - Contract.Requires(expr != null); - List l = new List(); - if (expr != null) { - l = GenerateBoundVarListForMining(expr, l); - } - return new ListOfMiningStrategies(l); - } - - public static List/*!*/ GenerateBoundVarListForMining(Expr expr, List l) { - Contract.Requires(l != null); - Contract.Requires(expr != null); - Contract.Ensures(Contract.Result>() != null); - - // go through the origExpr and identify all bound variables in the AST. - if (expr is LiteralExpr || expr is IdentifierExpr) { - //end recursion - } else if (expr is NAryExpr) { - NAryExpr e = (NAryExpr)expr; - foreach (Expr/*!*/ arg in e.Args) { - Contract.Assert(arg != null); - l = GenerateBoundVarListForMining(arg, l); - } - } else if (expr is OldExpr) { - OldExpr e = (OldExpr)expr; - l = GenerateBoundVarListForMining(e.Expr, l); - } else if (expr is QuantifierExpr) { - QuantifierExpr qe = (QuantifierExpr)expr; - List vs = qe.Dummies; - foreach (Variable/*!*/ x in vs) { - Contract.Assert(x != null); - string name = x.Name; - if (name.StartsWith("^")) { - name = name.Substring(1); - List exprList = new List(); - exprList.Add(new IdentifierExpr(Token.NoToken, x.ToString(), x.TypedIdent.Type)); - MiningStrategy eed = new EEDTemplate("The bound variable " + name + " has the value {0}.", exprList); - l.Add(eed); - } - } - l = GenerateBoundVarListForMining(qe.Body, l); - } - return l; - } - - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssertCmd(this); - } - } - - // An AssertCmd that is a loop invariant check before the loop iteration starts - public class LoopInitAssertCmd : AssertCmd { - public LoopInitAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - } - - // An AssertCmd that is a loop invariant check to maintain the invariant after iteration - public class LoopInvMaintainedAssertCmd : AssertCmd { - public LoopInvMaintainedAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - } - - /// - /// An AssertCmd that is introduced in translation from the requires on a call. - /// - public class AssertRequiresCmd : AssertCmd { - public CallCmd/*!*/ Call; - public Requires/*!*/ Requires; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Call != null); - Contract.Invariant(Requires != null); - } - - - public AssertRequiresCmd(CallCmd/*!*/ call, Requires/*!*/ requires) - : base(call.tok, requires.Condition) { - Contract.Requires(call != null); - Contract.Requires(requires != null); - this.Call = call; - this.Requires = requires; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssertRequiresCmd(this); - } - } - - /// - /// An AssertCmd that is introduced in translation from an ensures - /// declaration. - /// - public class AssertEnsuresCmd : AssertCmd { - public Ensures/*!*/ Ensures; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Ensures != null); - } - - public AssertEnsuresCmd(Ensures/*!*/ ens) - : base(ens.tok, ens.Condition) { - Contract.Requires(ens != null); - this.Ensures = ens; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssertEnsuresCmd(this); - } - } - - public class AssumeCmd : PredicateCmd { - public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok, expr) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) - : base(tok, expr, kv) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "assume "); - EmitAttributes(stream, Attributes); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "an assumed expression must be of type bool (got: {0})", Expr.Type); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitAssumeCmd(this); - } - } - - public class ReturnExprCmd : ReturnCmd { - public Expr/*!*/ Expr; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Expr != null); - } - - public ReturnExprCmd(IToken/*!*/ tok, Expr/*!*/ expr) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - Expr = expr; - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "return "); - this.Expr.Emit(stream); - stream.WriteLine(";"); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Expr.Typecheck(tc); - Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition - if (!Expr.Type.Unify(Type.Bool)) { - tc.Error(this, "a return expression must be of type bool (got: {0})", Expr.Type); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Expr.Resolve(rc); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitReturnExprCmd(this); - } - } - - public class HavocCmd : Cmd { - private List/*!*/ _vars; - - public List/*!*/ Vars { - get { - Contract.Ensures(Contract.Result>() != null); - return this._vars; - } - set { - Contract.Requires(value != null); - this._vars = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._vars != null); - } - - public HavocCmd(IToken/*!*/ tok, List/*!*/ vars) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(vars != null); - this._vars = vars; - } - - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.Write(this, level, "havoc "); - Vars.Emit(stream, true); - stream.WriteLine(";"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - foreach (IdentifierExpr/*!*/ ide in Vars) { - Contract.Assert(ide != null); - ide.Resolve(rc); - } - } - public override void AddAssignedVariables(List vars) { - //Contract.Requires(vars != null); - foreach (IdentifierExpr/*!*/ e in this.Vars) { - Contract.Assert(e != null); - vars.Add(e.Decl); - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (IdentifierExpr ie in Vars) - { - ie.Typecheck(tc); - } - this.CheckAssignments(tc); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitHavocCmd(this); - } - } - - //--------------------------------------------------------------------- - // Transfer commands - [ContractClass(typeof(TransferCmdContracts))] - public abstract class TransferCmd : Absy { - internal TransferCmd(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - public abstract void Emit(TokenTextWriter/*!*/ stream, int level); - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - // nothing to typecheck - } - - public override string ToString() - { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { - this.Emit(stream, 0); - } - return buffer.ToString(); - } - } - [ContractClassFor(typeof(TransferCmd))] - public abstract class TransferCmdContracts : TransferCmd { - public TransferCmdContracts() :base(null){ - - } - public override void Emit(TokenTextWriter stream, int level) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - } - - public class ReturnCmd : TransferCmd { - public ReturnCmd(IToken/*!*/ tok) - : base(tok) { - Contract.Requires(tok != null); - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - stream.WriteLine(this, level, "return;"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - // nothing to resolve - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitReturnCmd(this); - } - } - - public class GotoCmd : TransferCmd { - [Rep] - public List labelNames; - [Rep] - public List labelTargets; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(labelNames == null || labelTargets == null || labelNames.Count == labelTargets.Count); - } - - [NotDelayed] - public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(labelSeq != null); - this.labelNames = labelSeq; - } - public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq, List/*!*/ blockSeq) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(labelSeq != null); - Contract.Requires(blockSeq != null); - Debug.Assert(labelSeq.Count == blockSeq.Count); - for (int i = 0; i < labelSeq.Count; i++) { - Debug.Assert(Equals(labelSeq[i], cce.NonNull(blockSeq[i]).Label)); - } - - this.labelNames = labelSeq; - this.labelTargets = blockSeq; - } - public GotoCmd(IToken/*!*/ tok, List/*!*/ blockSeq) - : base(tok) { //requires (blockSeq[i] != null ==> blockSeq[i].Label != null); - Contract.Requires(tok != null); - Contract.Requires(blockSeq != null); - List labelSeq = new List(); - for (int i = 0; i < blockSeq.Count; i++) - labelSeq.Add(cce.NonNull(blockSeq[i]).Label); - this.labelNames = labelSeq; - this.labelTargets = blockSeq; - } - public void AddTarget(Block b) { - Contract.Requires(b != null); - Contract.Requires(b.Label != null); - Contract.Requires(this.labelTargets != null); - Contract.Requires(this.labelNames != null); - this.labelTargets.Add(b); - this.labelNames.Add(b.Label); - } - public override void Emit(TokenTextWriter stream, int level) { - //Contract.Requires(stream != null); - Contract.Assume(this.labelNames != null); - stream.Write(this, level, "goto "); - if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { - if (labelTargets == null) { - string sep = ""; - foreach (string name in labelNames) { - stream.Write("{0}{1}^^{2}", sep, "NoDecl", name); - sep = ", "; - } - } else { - string sep = ""; - foreach (Block/*!*/ b in labelTargets) { - Contract.Assert(b != null); - stream.Write("{0}h{1}^^{2}", sep, b.GetHashCode(), b.Label); - sep = ", "; - } - } - } else { - labelNames.Emit(stream); - } - stream.WriteLine(";"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(labelTargets != null); - if (labelTargets != null) { - // already resolved - return; - } - Contract.Assume(this.labelNames != null); - labelTargets = new List(); - foreach (string/*!*/ lbl in labelNames) { - Contract.Assert(lbl != null); - Block b = rc.LookUpBlock(lbl); - if (b == null) { - rc.Error(this, "goto to unknown block: {0}", lbl); - } else { - labelTargets.Add(b); - } - } - Debug.Assert(rc.ErrorCount > 0 || labelTargets.Count == labelNames.Count); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitGotoCmd(this); - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using System.Linq; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + using Set = GSet; + + + //--------------------------------------------------------------------- + // BigBlock + public class BigBlock { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + Contract.Invariant(Anonymous || this.labelName != null); + Contract.Invariant(this._ec == null || this._tc == null); + Contract.Invariant(this._simpleCmds != null); + } + + public readonly IToken/*!*/ tok; + + public readonly bool Anonymous; + + private string labelName; + + public string LabelName + { + get + { + Contract.Ensures(Anonymous || Contract.Result() != null); + return this.labelName; + } + set + { + Contract.Requires(Anonymous || value != null); + this.labelName = value; + } + } + + [Rep] + private List/*!*/ _simpleCmds; + + public List/*!*/ simpleCmds + { + get + { + Contract.Ensures(Contract.Result>() != null); + return this._simpleCmds; + } + set + { + Contract.Requires(value != null); + this._simpleCmds = value; + } + } + + private StructuredCmd _ec; + + public StructuredCmd ec + { + get + { + return this._ec; + } + set + { + Contract.Requires(value == null || this.tc == null); + this._ec = value; + } + } + + private TransferCmd _tc; + + public TransferCmd tc + { + get + { + return this._tc; + } + set + { + Contract.Requires(value == null || this.ec == null); + this._tc = value; + } + } + + public BigBlock successorBigBlock; // semantic successor (may be a back-edge, pointing back to enclosing while statement); null if successor is end of procedure body (or if field has not yet been initialized) + + public BigBlock(IToken tok, string labelName, [Captured] List simpleCmds, StructuredCmd ec, TransferCmd tc) { + Contract.Requires(simpleCmds != null); + Contract.Requires(tok != null); + Contract.Requires(ec == null || tc == null); + this.tok = tok; + this.Anonymous = labelName == null; + this.labelName = labelName; + this._simpleCmds = simpleCmds; + this._ec = ec; + this._tc = tc; + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + if (!Anonymous) { + stream.WriteLine(level, "{0}:", + CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.LabelName) : this.LabelName); + } + + foreach (Cmd/*!*/ c in this.simpleCmds) { + Contract.Assert(c != null); + c.Emit(stream, level + 1); + } + + if (this.ec != null) { + this.ec.Emit(stream, level + 1); + } else if (this.tc != null) { + this.tc.Emit(stream, level + 1); + } + } + } + + public class StmtList { + [Rep] + private readonly List/*!*/ bigBlocks; + + public IList/*!*/ BigBlocks + { + get + { + Contract.Ensures(Contract.Result>() != null); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this.bigBlocks.AsReadOnly(); + } + } + + public List PrefixCommands; + public readonly IToken/*!*/ EndCurly; + public StmtList ParentContext; + public BigBlock ParentBigBlock; + + private readonly HashSet/*!*/ labels = new HashSet(); + + public void AddLabel(string label) + { + labels.Add(label); + } + + public IEnumerable/*!*/ Labels + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result/*!*/>())); + return this.labels.AsEnumerable(); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(EndCurly != null); + Contract.Invariant(cce.NonNullElements(this.bigBlocks)); + Contract.Invariant(cce.NonNullElements(this.labels)); + } + + public StmtList(IList/*!*/ bigblocks, IToken endCurly) { + Contract.Requires(endCurly != null); + Contract.Requires(cce.NonNullElements(bigblocks)); + Contract.Requires(bigblocks.Count > 0); + this.bigBlocks = new List(bigblocks); + this.EndCurly = endCurly; + } + + // prints the list of statements, not the surrounding curly braces + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + bool needSeperator = false; + foreach (BigBlock b in BigBlocks) { + Contract.Assert(b != null); + Contract.Assume(cce.IsPeerConsistent(b)); + if (needSeperator) { + stream.WriteLine(); + } + b.Emit(stream, level); + needSeperator = true; + } + } + + /// + /// Tries to insert the commands "prefixCmds" at the beginning of the first block + /// of the StmtList, and returns "true" iff it succeeded. + /// In the event of success, the "suggestedLabel" returns as the name of the + /// block inside StmtList where "prefixCmds" were inserted. This name may be the + /// same as the one passed in, in case this StmtList has no preference as to what + /// to call its first block. In the event of failure, "suggestedLabel" is returned + /// as its input value. + /// Note, to be conservative (that is, ignoring the possible optimization that this + /// method enables), this method can do nothing and return false. + /// + public bool PrefixFirstBlock([Captured] List prefixCmds, ref string suggestedLabel) { + Contract.Requires(suggestedLabel != null); + Contract.Requires(prefixCmds != null); + Contract.Ensures(Contract.Result() || cce.Owner.None(prefixCmds)); // "prefixCmds" is captured only on success + Contract.Assume(PrefixCommands == null); // prefix has not been used + + BigBlock bb0 = BigBlocks[0]; + if (prefixCmds.Count == 0) { + // This is always a success, since there is nothing to insert. Now, decide + // which name to use for the first block. + if (bb0.Anonymous) { + bb0.LabelName = suggestedLabel; + } else { + Contract.Assert(bb0.LabelName != null); + suggestedLabel = bb0.LabelName; + } + return true; + + } else { + // There really is something to insert. We can do this inline only if the first + // block is anonymous (which implies there is no branch to it from within the block). + if (bb0.Anonymous) { + PrefixCommands = prefixCmds; + bb0.LabelName = suggestedLabel; + return true; + } else { + return false; + } + } + } + } + + /// + /// The AST for Boogie structured commands was designed to support backward compatibility with + /// the Boogie unstructured commands. This has made the structured commands hard to construct. + /// The StmtListBuilder class makes it easier to build structured commands. + /// + public class StmtListBuilder { + List/*!*/ bigBlocks = new List(); + string label; + List simpleCmds; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(bigBlocks)); + } + + void Dump(StructuredCmd scmd, TransferCmd tcmd) { + Contract.Requires(scmd == null || tcmd == null); + Contract.Ensures(label == null && simpleCmds == null); + if (label == null && simpleCmds == null && scmd == null && tcmd == null) { + // nothing to do + } else { + if (simpleCmds == null) { + simpleCmds = new List(); + } + bigBlocks.Add(new BigBlock(Token.NoToken, label, simpleCmds, scmd, tcmd)); + label = null; + simpleCmds = null; + } + } + + /// + /// Collects the StmtList built so far and returns it. The StmtListBuilder should no longer + /// be used once this method has been invoked. + /// + public StmtList Collect(IToken endCurlyBrace) { + Contract.Requires(endCurlyBrace != null); + Contract.Ensures(Contract.Result() != null); + Dump(null, null); + if (bigBlocks.Count == 0) { + simpleCmds = new List(); // the StmtList constructor doesn't like an empty list of BigBlock's + Dump(null, null); + } + return new StmtList(bigBlocks, endCurlyBrace); + } + + public void Add(Cmd cmd) { + Contract.Requires(cmd != null); + if (simpleCmds == null) { + simpleCmds = new List(); + } + simpleCmds.Add(cmd); + } + + public void Add(StructuredCmd scmd) { + Contract.Requires(scmd != null); + Dump(scmd, null); + } + + public void Add(TransferCmd tcmd) { + Contract.Requires(tcmd != null); + Dump(null, tcmd); + } + + public void AddLabelCmd(string label) { + Contract.Requires(label != null); + Dump(null, null); + this.label = label; + } + + public void AddLocalVariable(string name) { + Contract.Requires(name != null); + // TODO + } + } + + class BigBlocksResolutionContext { + StmtList/*!*/ stmtList; + [Peer] + List blocks; + string/*!*/ prefix = "anon"; + int anon = 0; + int FreshAnon() + { + return anon++; + } + HashSet allLabels = new HashSet(); + Errors/*!*/ errorHandler; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(stmtList != null); + Contract.Invariant(cce.NonNullElements(blocks, true)); + Contract.Invariant(prefix != null); + Contract.Invariant(cce.NonNullElements(allLabels, true)); + Contract.Invariant(errorHandler != null); + } + + private void ComputeAllLabels(StmtList stmts) { + if (stmts == null) return; + foreach (BigBlock bb in stmts.BigBlocks) { + if (bb.LabelName != null) { + allLabels.Add(bb.LabelName); + } + ComputeAllLabels(bb.ec); + } + } + + private void ComputeAllLabels(StructuredCmd cmd) { + if (cmd == null) return; + if (cmd is IfCmd) { + IfCmd ifCmd = (IfCmd)cmd; + ComputeAllLabels(ifCmd.thn); + ComputeAllLabels(ifCmd.elseIf); + ComputeAllLabels(ifCmd.elseBlock); + } + else if (cmd is WhileCmd) { + WhileCmd whileCmd = (WhileCmd)cmd; + ComputeAllLabels(whileCmd.Body); + } + } + + public BigBlocksResolutionContext(StmtList stmtList, Errors errorHandler) { + Contract.Requires(errorHandler != null); + Contract.Requires(stmtList != null); + this.stmtList = stmtList; + this.errorHandler = errorHandler; + ComputeAllLabels(stmtList); + } + + public List/*!*/ Blocks { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + if (blocks == null) { + blocks = new List(); + + int startErrorCount = this.errorHandler.count; + // Check that all goto statements go to a label in allLabels, and no break statement to a non-enclosing loop. + // Also, determine a good value for "prefix". + CheckLegalLabels(stmtList, null, null); + + // fill in names of anonymous blocks + NameAnonymousBlocks(stmtList); + + // determine successor blocks + RecordSuccessors(stmtList, null); + + if (this.errorHandler.count == startErrorCount) { + // generate blocks from the big blocks + CreateBlocks(stmtList, null); + } + } + return blocks; + } + } + + void CheckLegalLabels(StmtList stmtList, StmtList parentContext, BigBlock parentBigBlock) { + Contract.Requires(stmtList != null); + Contract.Requires((parentContext == null) == (parentBigBlock == null)); + Contract.Requires(stmtList.ParentContext == null); // it hasn't been set yet + //modifies stmtList.*; + Contract.Ensures(stmtList.ParentContext == parentContext); + stmtList.ParentContext = parentContext; + stmtList.ParentBigBlock = parentBigBlock; + + // record the labels declared in this StmtList + foreach (BigBlock b in stmtList.BigBlocks) { + if (b.LabelName != null) { + string n = b.LabelName; + if (n.StartsWith(prefix)) { + if (prefix.Length < n.Length && n[prefix.Length] == '0') { + prefix += "1"; + } else { + prefix += "0"; + } + } + stmtList.AddLabel(b.LabelName); + } + } + + // check that labels in this and nested StmtList's are legal + foreach (BigBlock b in stmtList.BigBlocks) { + // goto's must reference blocks in enclosing blocks + if (b.tc is GotoCmd) { + GotoCmd g = (GotoCmd)b.tc; + foreach (string/*!*/ lbl in cce.NonNull(g.labelNames)) { + Contract.Assert(lbl != null); + /* + bool found = false; + for (StmtList sl = stmtList; sl != null; sl = sl.ParentContext) { + if (sl.Labels.Contains(lbl)) { + found = true; + break; + } + } + if (!found) { + this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined or out of reach"); + } + */ + if (!allLabels.Contains(lbl)) { + this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined"); + } + } + } + + // break labels must refer to an enclosing while statement + else if (b.ec is BreakCmd) { + BreakCmd bcmd = (BreakCmd)b.ec; + Contract.Assert(bcmd.BreakEnclosure == null); // it hasn't been initialized yet + bool found = false; + for (StmtList sl = stmtList; sl.ParentBigBlock != null; sl = sl.ParentContext) { + cce.LoopInvariant(sl != null); + BigBlock bb = sl.ParentBigBlock; + + if (bcmd.Label == null) { + // a label-less break statement breaks out of the innermost enclosing while statement + if (bb.ec is WhileCmd) { + bcmd.BreakEnclosure = bb; + found = true; + break; + } + } else if (bcmd.Label == bb.LabelName) { + // a break statement with a label can break out of both if statements and while statements + if (bb.simpleCmds.Count == 0) { + // this is a good target: the label refers to the if/while statement + bcmd.BreakEnclosure = bb; + } else { + // the label of bb refers to the first statement of bb, which in which case is a simple statement, not an if/while statement + this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); + } + found = true; // don't look any further, since we've found a matching label + break; + } + } + if (!found) { + if (bcmd.Label == null) { + this.errorHandler.SemErr(bcmd.tok, "Error: break statement is not inside a loop"); + } else { + this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); + } + } + } + + // recurse + else if (b.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)b.ec; + CheckLegalLabels(wcmd.Body, stmtList, b); + } else { + for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { + CheckLegalLabels(ifcmd.thn, stmtList, b); + if (ifcmd.elseBlock != null) { + CheckLegalLabels(ifcmd.elseBlock, stmtList, b); + } + } + } + } + } + + void NameAnonymousBlocks(StmtList stmtList) { + Contract.Requires(stmtList != null); + foreach (BigBlock b in stmtList.BigBlocks) { + if (b.LabelName == null) { + b.LabelName = prefix + FreshAnon(); + } + if (b.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)b.ec; + NameAnonymousBlocks(wcmd.Body); + } else { + for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { + NameAnonymousBlocks(ifcmd.thn); + if (ifcmd.elseBlock != null) { + NameAnonymousBlocks(ifcmd.elseBlock); + } + } + } + } + } + + void RecordSuccessors(StmtList stmtList, BigBlock successor) { + Contract.Requires(stmtList != null); + for (int i = stmtList.BigBlocks.Count; 0 <= --i; ) { + BigBlock big = stmtList.BigBlocks[i]; + big.successorBigBlock = successor; + + if (big.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)big.ec; + RecordSuccessors(wcmd.Body, big); + } else { + for (IfCmd ifcmd = big.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { + RecordSuccessors(ifcmd.thn, successor); + if (ifcmd.elseBlock != null) { + RecordSuccessors(ifcmd.elseBlock, successor); + } + } + } + + successor = big; + } + } + + // If the enclosing context is a loop, then "runOffTheEndLabel" is the loop head label; + // otherwise, it is null. + void CreateBlocks(StmtList stmtList, string runOffTheEndLabel) { + Contract.Requires(stmtList != null); + Contract.Requires(blocks != null); + List cmdPrefixToApply = stmtList.PrefixCommands; + + int n = stmtList.BigBlocks.Count; + foreach (BigBlock b in stmtList.BigBlocks) { + n--; + Contract.Assert(b.LabelName != null); + List theSimpleCmds; + if (cmdPrefixToApply == null) { + theSimpleCmds = b.simpleCmds; + } else { + theSimpleCmds = new List(); + theSimpleCmds.AddRange(cmdPrefixToApply); + theSimpleCmds.AddRange(b.simpleCmds); + cmdPrefixToApply = null; // now, we've used 'em up + } + + if (b.tc != null) { + // this BigBlock has the very same components as a Block + Contract.Assert(b.ec == null); + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, b.tc); + blocks.Add(block); + + } else if (b.ec == null) { + TransferCmd trCmd; + if (n == 0 && runOffTheEndLabel != null) { + // goto the given label instead of the textual successor block + trCmd = new GotoCmd(stmtList.EndCurly, new List { runOffTheEndLabel }); + } else { + trCmd = GotoSuccessor(stmtList.EndCurly, b); + } + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, trCmd); + blocks.Add(block); + + } else if (b.ec is BreakCmd) { + BreakCmd bcmd = (BreakCmd)b.ec; + Contract.Assert(bcmd.BreakEnclosure != null); + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, GotoSuccessor(b.ec.tok, bcmd.BreakEnclosure)); + blocks.Add(block); + + } else if (b.ec is WhileCmd) { + WhileCmd wcmd = (WhileCmd)b.ec; + var a = FreshAnon(); + string loopHeadLabel = prefix + a + "_LoopHead"; + string/*!*/ loopBodyLabel = prefix + a + "_LoopBody"; + string loopDoneLabel = prefix + a + "_LoopDone"; + + List ssBody = new List(); + List ssDone = new List(); + if (wcmd.Guard != null) { + var ac = new AssumeCmd(wcmd.tok, wcmd.Guard); + ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); + ssBody.Add(ac); + + ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard)); + ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List(), null); + ssDone.Add(ac); + } + + // Try to squeeze in ssBody into the first block of wcmd.Body + bool bodyGuardTakenCareOf = wcmd.Body.PrefixFirstBlock(ssBody, ref loopBodyLabel); + + // ... goto LoopHead; + Block block = new Block(b.tok, b.LabelName, theSimpleCmds, new GotoCmd(wcmd.tok, new List { loopHeadLabel })); + blocks.Add(block); + + // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody; + List ssHead = new List(); + foreach (PredicateCmd inv in wcmd.Invariants) { + ssHead.Add(inv); + } + block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List { loopDoneLabel, loopBodyLabel })); + blocks.Add(block); + + if (!bodyGuardTakenCareOf) { + // LoopBody: assume guard; goto firstLoopBlock; + block = new Block(wcmd.tok, loopBodyLabel, ssBody, new GotoCmd(wcmd.tok, new List { wcmd.Body.BigBlocks[0].LabelName })); + blocks.Add(block); + } + + // recurse to create the blocks for the loop body + CreateBlocks(wcmd.Body, loopHeadLabel); + + // LoopDone: assume !guard; goto loopSuccessor; + TransferCmd trCmd; + if (n == 0 && runOffTheEndLabel != null) { + // goto the given label instead of the textual successor block + trCmd = new GotoCmd(wcmd.tok, new List { runOffTheEndLabel }); + } else { + trCmd = GotoSuccessor(wcmd.tok, b); + } + block = new Block(wcmd.tok, loopDoneLabel, ssDone, trCmd); + blocks.Add(block); + + } else { + IfCmd ifcmd = (IfCmd)b.ec; + string predLabel = b.LabelName; + List predCmds = theSimpleCmds; + + for (; ifcmd != null; ifcmd = ifcmd.elseIf) { + var a = FreshAnon(); + string thenLabel = prefix + a + "_Then"; + Contract.Assert(thenLabel != null); + string elseLabel = prefix + a + "_Else"; + Contract.Assert(elseLabel != null); + + List ssThen = new List(); + List ssElse = new List(); + if (ifcmd.Guard != null) { + var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard); + ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); + ssThen.Add(ac); + + ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); + ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); + ssElse.Add(ac); + } + + // Try to squeeze in ssThen/ssElse into the first block of ifcmd.thn/ifcmd.elseBlock + bool thenGuardTakenCareOf = ifcmd.thn.PrefixFirstBlock(ssThen, ref thenLabel); + bool elseGuardTakenCareOf = false; + if (ifcmd.elseBlock != null) { + elseGuardTakenCareOf = ifcmd.elseBlock.PrefixFirstBlock(ssElse, ref elseLabel); + } + + // ... goto Then, Else; + Block block = new Block(b.tok, predLabel, predCmds, + new GotoCmd(ifcmd.tok, new List { thenLabel, elseLabel })); + blocks.Add(block); + + if (!thenGuardTakenCareOf) { + // Then: assume guard; goto firstThenBlock; + block = new Block(ifcmd.tok, thenLabel, ssThen, new GotoCmd(ifcmd.tok, new List { ifcmd.thn.BigBlocks[0].LabelName })); + blocks.Add(block); + } + + // recurse to create the blocks for the then branch + CreateBlocks(ifcmd.thn, n == 0 ? runOffTheEndLabel : null); + + if (ifcmd.elseBlock != null) { + Contract.Assert(ifcmd.elseIf == null); + if (!elseGuardTakenCareOf) { + // Else: assume !guard; goto firstElseBlock; + block = new Block(ifcmd.tok, elseLabel, ssElse, new GotoCmd(ifcmd.tok, new List { ifcmd.elseBlock.BigBlocks[0].LabelName })); + blocks.Add(block); + } + + // recurse to create the blocks for the else branch + CreateBlocks(ifcmd.elseBlock, n == 0 ? runOffTheEndLabel : null); + + } else if (ifcmd.elseIf != null) { + // this is an "else if" + predLabel = elseLabel; + predCmds = new List(); + if (ifcmd.Guard != null) { + var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); + ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List(), null); + predCmds.Add(ac); + } + + } else { + // no else alternative is specified, so else branch is just "skip" + // Else: assume !guard; goto ifSuccessor; + TransferCmd trCmd; + if (n == 0 && runOffTheEndLabel != null) { + // goto the given label instead of the textual successor block + trCmd = new GotoCmd(ifcmd.tok, new List { runOffTheEndLabel }); + } else { + trCmd = GotoSuccessor(ifcmd.tok, b); + } + block = new Block(ifcmd.tok, elseLabel, ssElse, trCmd); + blocks.Add(block); + } + } + } + } + } + + TransferCmd GotoSuccessor(IToken tok, BigBlock b) { + Contract.Requires(b != null); + Contract.Requires(tok != null); + Contract.Ensures(Contract.Result() != null); + if (b.successorBigBlock != null) { + return new GotoCmd(tok, new List { b.successorBigBlock.LabelName }); + } else { + return new ReturnCmd(tok); + } + } + } + + [ContractClass(typeof(StructuredCmdContracts))] + public abstract class StructuredCmd { + private IToken/*!*/ _tok; + + public IToken/*!*/ tok + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._tok; + } + set + { + Contract.Requires(value != null); + this._tok = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._tok != null); + } + + public StructuredCmd(IToken tok) { + Contract.Requires(tok != null); + this._tok = tok; + } + + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + } + [ContractClassFor(typeof(StructuredCmd))] + public abstract class StructuredCmdContracts : StructuredCmd { + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + public StructuredCmdContracts() :base(null){ + + } + } + + public class IfCmd : StructuredCmd { + public Expr Guard; + + private StmtList/*!*/ _thn; + + public StmtList/*!*/ thn + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._thn; + } + set + { + Contract.Requires(value != null); + this._thn = value; + } + } + + private IfCmd _elseIf; + + public IfCmd elseIf + { + get + { + return this._elseIf; + } + set + { + Contract.Requires(value == null || this.elseBlock == null); + this._elseIf = value; + } + } + + private StmtList _elseBlock; + + public StmtList elseBlock + { + get + { + return this._elseBlock; + } + set + { + Contract.Requires(value == null || this.elseIf == null); + this._elseBlock = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._thn != null); + Contract.Invariant(this._elseIf == null || this._elseBlock == null); + } + + public IfCmd(IToken/*!*/ tok, Expr guard, StmtList/*!*/ thn, IfCmd elseIf, StmtList elseBlock) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(thn != null); + Contract.Requires(elseIf == null || elseBlock == null); + this.Guard = guard; + this._thn = thn; + this._elseIf = elseIf; + this._elseBlock = elseBlock; + } + + public override void Emit(TokenTextWriter stream, int level) { + stream.Write(level, "if ("); + IfCmd/*!*/ ifcmd = this; + while (true) { + if (ifcmd.Guard == null) { + stream.Write("*"); + } else { + ifcmd.Guard.Emit(stream); + } + stream.WriteLine(")"); + + stream.WriteLine(level, "{"); + ifcmd.thn.Emit(stream, level + 1); + stream.WriteLine(level, "}"); + + if (ifcmd.elseIf != null) { + stream.Write(level, "else if ("); + ifcmd = ifcmd.elseIf; + continue; + } else if (ifcmd.elseBlock != null) { + stream.WriteLine(level, "else"); + stream.WriteLine(level, "{"); + ifcmd.elseBlock.Emit(stream, level + 1); + stream.WriteLine(level, "}"); + } + break; + } + } + } + + public class WhileCmd : StructuredCmd { + [Peer] + public Expr Guard; + public List/*!*/ Invariants; + public StmtList/*!*/ Body; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Body != null); + Contract.Invariant(cce.NonNullElements(Invariants)); + } + + + public WhileCmd(IToken tok, [Captured] Expr guard, List/*!*/ invariants, StmtList/*!*/ body) + : base(tok) { + Contract.Requires(cce.NonNullElements(invariants)); + Contract.Requires(body != null); + Contract.Requires(tok != null); + this.Guard = guard; + this.Invariants = invariants; + this.Body = body; + } + + public override void Emit(TokenTextWriter stream, int level) { + stream.Write(level, "while ("); + if (Guard == null) { + stream.Write("*"); + } else { + Guard.Emit(stream); + } + stream.WriteLine(")"); + + foreach (PredicateCmd inv in Invariants) { + if (inv is AssumeCmd) { + stream.Write(level + 1, "free invariant "); + } else { + stream.Write(level + 1, "invariant "); + } + Cmd.EmitAttributes(stream, inv.Attributes); + inv.Expr.Emit(stream); + stream.WriteLine(";"); + } + + stream.WriteLine(level, "{"); + Body.Emit(stream, level + 1); + stream.WriteLine(level, "}"); + } + } + + public class BreakCmd : StructuredCmd { + public string Label; + public BigBlock BreakEnclosure; + + public BreakCmd(IToken tok, string label) + : base(tok) { + Contract.Requires(tok != null); + this.Label = label; + } + + public override void Emit(TokenTextWriter stream, int level) { + + if (Label == null) { + stream.WriteLine(level, "break;"); + } else { + stream.WriteLine(level, "break {0};", Label); + } + } + } + + //--------------------------------------------------------------------- + // Block + public sealed class Block : Absy { + private string/*!*/ label; // Note, Label is mostly readonly, but it can change to the name of a nearby block during block coalescing and empty-block removal + + public string/*!*/ Label + { + get + { + Contract.Ensures(Contract.Result() != null); + return this.label; + } + set + { + Contract.Requires(value != null); + this.label = value; + } + } + + [Rep] + [ElementsPeer] + public List/*!*/ cmds; + + public List/*!*/ Cmds + { + get + { + Contract.Ensures(Contract.Result>() != null); + return this.cmds; + } + set + { + Contract.Requires(value != null); + this.cmds = value; + } + } + + [Rep] //PM: needed to verify Traverse.Visit + public TransferCmd TransferCmd; // maybe null only because we allow deferred initialization (necessary for cyclic structures) + + public byte[] Checksum; + + // Abstract interpretation + + // public bool currentlyTraversed; + + public enum VisitState { + ToVisit, + BeingVisited, + AlreadyVisited + }; // used by WidenPoints.Compute + public VisitState TraversingStatus; + + public int aiId; // block ID used by the abstract interpreter, which may change these numbers with each AI run + public bool widenBlock; + public int iterations; // Count the number of time we visited the block during fixpoint computation. Used to decide if we widen or not + + // VC generation and SCC computation + public List/*!*/ Predecessors; + + // This field is used during passification to null-out entries in block2Incartion hashtable early + public int succCount; + + private HashSet _liveVarsBefore; + + public IEnumerable liveVarsBefore + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>(), true)); + if (this._liveVarsBefore == null) + return null; + else + return this._liveVarsBefore.AsEnumerable(); + } + set + { + Contract.Requires(cce.NonNullElements(value, true)); + if (value == null) + this._liveVarsBefore = null; + else + this._liveVarsBefore = new HashSet(value); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.label != null); + Contract.Invariant(this.cmds != null); + Contract.Invariant(cce.NonNullElements(this._liveVarsBefore, true)); + } + + public bool IsLive(Variable v) { + Contract.Requires(v != null); + if (liveVarsBefore == null) + return true; + return liveVarsBefore.Contains(v); + } + + public Block() + : this(Token.NoToken, "", new List(), new ReturnCmd(Token.NoToken)) { + + } + + public Block(IToken tok, string/*!*/ label, List/*!*/ cmds, TransferCmd transferCmd) + : base(tok) { + Contract.Requires(label != null); + Contract.Requires(cmds != null); + Contract.Requires(tok != null); + this.label = label; + this.cmds = cmds; + this.TransferCmd = transferCmd; + this.Predecessors = new List(); + this._liveVarsBefore = null; + this.TraversingStatus = VisitState.ToVisit; + this.iterations = 0; + } + + public void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + stream.WriteLine(); + stream.WriteLine( + this, + level, + "{0}:{1}", + CommandLineOptions.Clo.PrintWithUniqueASTIds ? String.Format("h{0}^^{1}", this.GetHashCode(), this.Label) : this.Label, + this.widenBlock ? " // cut point" : ""); + + foreach (Cmd/*!*/ c in this.Cmds) { + Contract.Assert(c != null); + c.Emit(stream, level + 1); + } + Contract.Assume(this.TransferCmd != null); + this.TransferCmd.Emit(stream, level + 1); + } + + public void Register(ResolutionContext rc) { + Contract.Requires(rc != null); + rc.AddBlock(this); + } + + public override void Resolve(ResolutionContext rc) { + + + foreach (Cmd/*!*/ c in Cmds) { + Contract.Assert(c != null); + c.Resolve(rc); + } + Contract.Assume(this.TransferCmd != null); + TransferCmd.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + + foreach (Cmd/*!*/ c in Cmds) { + Contract.Assert(c != null); + c.Typecheck(tc); + } + Contract.Assume(this.TransferCmd != null); + TransferCmd.Typecheck(tc); + } + + /// + /// Reset the abstract intepretation state of this block. It does this by putting the iterations to 0 and the pre and post states to null + /// + public void ResetAbstractInterpretationState() { + // this.currentlyTraversed = false; + this.TraversingStatus = VisitState.ToVisit; + this.iterations = 0; + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return this.Label + (this.widenBlock ? "[w]" : ""); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBlock(this); + } + } + + //--------------------------------------------------------------------- + // Commands + [ContractClassFor(typeof(Cmd))] + public abstract class CmdContracts : Cmd { + public CmdContracts() :base(null){ + + } + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + public override void AddAssignedVariables(List vars) { + Contract.Requires(vars != null); + throw new NotImplementedException(); + } + } + + public static class ChecksumHelper + { + public static void ComputeChecksums(Cmd cmd, Implementation impl, ISet usedVariables, byte[] currentChecksum = null) + { + if (CommandLineOptions.Clo.VerifySnapshots < 2) + { + return; + } + + if (cmd.IrrelevantForChecksumComputation) + { + cmd.Checksum = currentChecksum; + return; + } + + var assumeCmd = cmd as AssumeCmd; + if (assumeCmd != null + && QKeyValue.FindBoolAttribute(assumeCmd.Attributes, "assumption_variable_initialization")) + { + // Ignore assumption variable initializations. + assumeCmd.Checksum = currentChecksum; + return; + } + + using (var strWr = new System.IO.StringWriter()) + using (var tokTxtWr = new TokenTextWriter("", strWr, false, false)) + { + tokTxtWr.UseForComputingChecksums = true; + var havocCmd = cmd as HavocCmd; + if (havocCmd != null) + { + tokTxtWr.Write("havoc "); + var relevantVars = havocCmd.Vars.Where(e => usedVariables.Contains(e.Decl) && !e.Decl.Name.StartsWith("a##cached##")).OrderBy(e => e.Name).ToList(); + relevantVars.Emit(tokTxtWr, true); + tokTxtWr.WriteLine(";"); + } + else + { + cmd.Emit(tokTxtWr, 0); + } + var md5 = System.Security.Cryptography.MD5.Create(); + var str = strWr.ToString(); + if (str.Any()) + { + var data = System.Text.Encoding.UTF8.GetBytes(str); + var checksum = md5.ComputeHash(data); + currentChecksum = currentChecksum != null ? CombineChecksums(currentChecksum, checksum) : checksum; + } + cmd.Checksum = currentChecksum; + } + + var assertCmd = cmd as AssertCmd; + if (assertCmd != null && assertCmd.Checksum != null) + { + var assertRequiresCmd = assertCmd as AssertRequiresCmd; + if (assertRequiresCmd != null) + { + impl.AddAssertionChecksum(assertRequiresCmd.Checksum); + impl.AddAssertionChecksum(assertRequiresCmd.Call.Checksum); + assertRequiresCmd.SugaredCmdChecksum = assertRequiresCmd.Call.Checksum; + } + else + { + impl.AddAssertionChecksum(assertCmd.Checksum); + } + } + + var sugaredCmd = cmd as SugaredCmd; + if (sugaredCmd != null) + { + // The checksum of a sugared command should not depend on the desugaring itself. + var stateCmd = sugaredCmd.Desugaring as StateCmd; + if (stateCmd != null) + { + foreach (var c in stateCmd.Cmds) + { + ComputeChecksums(c, impl, usedVariables, currentChecksum); + currentChecksum = c.Checksum; + if (c.SugaredCmdChecksum == null) + { + c.SugaredCmdChecksum = cmd.Checksum; + } + } + } + else + { + ComputeChecksums(sugaredCmd.Desugaring, impl, usedVariables, currentChecksum); + } + } + } + + public static byte[] CombineChecksums(byte[] first, byte[] second, bool unordered = false) + { + Contract.Requires(first != null && (second == null || first.Length == second.Length)); + + var result = (byte[])(first.Clone()); + for (int i = 0; second != null && i < second.Length; i++) + { + if (unordered) + { + result[i] += second[i]; + } + else + { + result[i] = (byte)(result[i] * 31 ^ second[i]); + } + } + return result; + } + } + + [ContractClass(typeof(CmdContracts))] + public abstract class Cmd : Absy { + public byte[] Checksum { get; internal set; } + public byte[] SugaredCmdChecksum { get; internal set; } + public bool IrrelevantForChecksumComputation { get; set; } + + public Cmd(IToken/*!*/ tok) + : base(tok) { + Contract.Assert(tok != null); + } + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + public abstract void AddAssignedVariables(List/*!*/ vars); + public void CheckAssignments(TypecheckingContext tc) + { + Contract.Requires(tc != null); + List/*!*/ vars = new List(); + this.AddAssignedVariables(vars); + foreach (Variable/*!*/ v in vars) + { + Contract.Assert(v != null); + if (!v.IsMutable) + { + tc.Error(this, "command assigns to an immutable variable: {0}", v.Name); + } + else if (!CommandLineOptions.Clo.DoModSetAnalysis && v is GlobalVariable) + { + if (tc.Yields) { + // a yielding procedure is allowed to modify any global variable + } + else if (tc.Frame == null) + { + tc.Error(this, "update to a global variable allowed only inside an atomic action of a yielding procedure"); + } + else if (!tc.InFrame(v)) + { + tc.Error(this, "command assigns to a global variable that is not in the enclosing procedure's modifies clause: {0}", v.Name); + } + } + } + } + + // Methods to simulate the old SimpleAssignCmd and MapAssignCmd + public static AssignCmd SimpleAssign(IToken tok, IdentifierExpr lhs, Expr rhs) { + Contract.Requires(rhs != null); + Contract.Requires(lhs != null); + Contract.Requires(tok != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ lhss = new List(); + List/*!*/ rhss = new List(); + + lhss.Add(new SimpleAssignLhs(lhs.tok, lhs)); + rhss.Add(rhs); + + return new AssignCmd(tok, lhss, rhss); + } + + public static AssignCmd/*!*/ MapAssign(IToken tok, + IdentifierExpr/*!*/ map, + List/*!*/ indexes, Expr/*!*/ rhs) { + + Contract.Requires(tok != null); + Contract.Requires(map != null); + Contract.Requires(indexes != null); + Contract.Requires(rhs != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ lhss = new List(); + List/*!*/ rhss = new List(); + List/*!*/ indexesList = new List(); + + + + foreach (Expr e in indexes) + indexesList.Add(cce.NonNull(e)); + + lhss.Add(new MapAssignLhs(map.tok, + new SimpleAssignLhs(map.tok, map), + indexesList)); + rhss.Add(rhs); + + return new AssignCmd(tok, lhss, rhss); + } + + public static AssignCmd/*!*/ MapAssign(IToken tok, + IdentifierExpr/*!*/ map, + params Expr[]/*!*/ args) { + Contract.Requires(tok != null); + Contract.Requires(map != null); + Contract.Requires(args != null); + Contract.Requires(args.Length > 0); // at least the rhs + Contract.Requires(Contract.ForAll(args, i => i != null)); + Contract.Ensures(Contract.Result() != null); + + List/*!*/ lhss = new List(); + List/*!*/ rhss = new List(); + List/*!*/ indexesList = new List(); + + for (int i = 0; i < args.Length - 1; ++i) + indexesList.Add(cce.NonNull(args[i])); + + lhss.Add(new MapAssignLhs(map.tok, + new SimpleAssignLhs(map.tok, map), + indexesList)); + rhss.Add(cce.NonNull(args[args.Length - 1])); + + return new AssignCmd(tok, lhss, rhss); + } + + /// + /// This is a helper routine for printing a linked list of attributes. Each attribute + /// is terminated by a space. + /// + public static void EmitAttributes(TokenTextWriter stream, QKeyValue attributes) { + Contract.Requires(stream != null); + + if (stream.UseForComputingChecksums) { return; } + + for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { + kv.Emit(stream); + stream.Write(" "); + } + } + public static void ResolveAttributes(QKeyValue attributes, ResolutionContext rc) { + Contract.Requires(rc != null); + for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { + kv.Resolve(rc); + } + } + public static void TypecheckAttributes(QKeyValue attributes, TypecheckingContext tc) { + Contract.Requires(tc != null); + for (QKeyValue kv = attributes; kv != null; kv = kv.Next) { + kv.Typecheck(tc); + } + } + + [Pure] + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { + this.Emit(stream, 0); + } + return buffer.ToString(); + } + } + + public class YieldCmd : Cmd + { + public YieldCmd(IToken/*!*/ tok) + : base(tok) + { + Contract.Requires(tok != null); + } + public override void Emit(TokenTextWriter stream, int level) + { + //Contract.Requires(stream != null); + stream.WriteLine(this, level, "yield;"); + } + public override void Resolve(ResolutionContext rc) + { + // nothing to resolve + } + public override void Typecheck(TypecheckingContext tc) + { + if (!CommandLineOptions.Clo.DoModSetAnalysis && !tc.Yields) + { + tc.Error(this, "enclosing procedure of a yield command must yield"); + } + } + public override void AddAssignedVariables(List vars) + { + // nothing to add + } + public override Absy StdDispatch(StandardVisitor visitor) + { + Contract.Ensures(Contract.Result() != null); + return visitor.VisitYieldCmd(this); + } + } + + public class CommentCmd : Cmd // just a convenience for debugging + { + public readonly string/*!*/ Comment; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Comment != null); + } + + public CommentCmd(string c) + : base(Token.NoToken) { + Contract.Requires(c != null); + Comment = c; + } + public override void Emit(TokenTextWriter stream, int level) { + if (stream.UseForComputingChecksums) { return; } + + if (this.Comment.Contains("\n")) { + stream.WriteLine(this, level, "/* {0} */", this.Comment); + } else { + stream.WriteLine(this, level, "// {0}", this.Comment); + } + } + public override void Resolve(ResolutionContext rc) { + + } + public override void AddAssignedVariables(List vars) { + + } + public override void Typecheck(TypecheckingContext tc) { + + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + + return visitor.VisitCommentCmd(this); + } + } + + // class for parallel assignments, which subsumes both the old + // SimpleAssignCmd and the old MapAssignCmd + public class AssignCmd : Cmd { + private List/*!*/ _lhss; + + public IList/*!*/ Lhss { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this._lhss.AsReadOnly(); + } + set { + Contract.Requires(cce.NonNullElements(value)); + this._lhss = new List(value); + } + } + + internal void SetLhs(int index, AssignLhs lhs) + { + Contract.Requires(0 <= index && index < this.Lhss.Count); + Contract.Requires(lhs != null); + Contract.Ensures(this.Lhss[index] == lhs); + this._lhss[index] = lhs; + } + + private List/*!*/ _rhss; + + public IList/*!*/ Rhss { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this._rhss.AsReadOnly(); + } + set { + Contract.Requires(cce.NonNullElements(value)); + this._rhss = new List(value); + } + } + + internal void SetRhs(int index, Expr rhs) + { + Contract.Requires(0 <= index && index < this.Rhss.Count); + Contract.Requires(rhs != null); + Contract.Ensures(this.Rhss[index] == rhs); + this._rhss[index] = rhs; + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(this._lhss)); + Contract.Invariant(cce.NonNullElements(this._rhss)); + } + + + public AssignCmd(IToken tok, IList/*!*/ lhss, IList/*!*/ rhss) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(rhss)); + Contract.Requires(cce.NonNullElements(lhss)); + this._lhss = new List(lhss); + this._rhss = new List(rhss); + } + + public override void Emit(TokenTextWriter stream, int level) { + stream.Write(this, level, ""); + + string/*!*/ sep = ""; + foreach (AssignLhs/*!*/ l in Lhss) { + Contract.Assert(l != null); + stream.Write(sep); + sep = ", "; + l.Emit(stream); + } + + stream.Write(" := "); + + sep = ""; + foreach (Expr/*!*/ e in Rhss) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + } + + stream.WriteLine(";"); + } + + public override void Resolve(ResolutionContext rc) { + + if (Lhss.Count != Rhss.Count) + rc.Error(this, + "number of left-hand sides does not match number of right-hand sides"); + + foreach (AssignLhs/*!*/ e in Lhss) { + Contract.Assert(e != null); + e.Resolve(rc); + } + foreach (Expr/*!*/ e in Rhss) { + Contract.Assert(e != null); + e.Resolve(rc); + } + + // check for double occurrences of assigned variables + // (could be optimised) + for (int i = 0; i < Lhss.Count; ++i) { + for (int j = i + 1; j < Lhss.Count; ++j) { + if (cce.NonNull(Lhss[i].DeepAssignedVariable).Equals( + Lhss[j].DeepAssignedVariable)) + rc.Error(Lhss[j], + "variable {0} is assigned more than once in parallel assignment", + Lhss[j].DeepAssignedVariable); + } + } + + for (int i = 0; i < Lhss.Count; i++) + { + var lhs = Lhss[i].AsExpr as IdentifierExpr; + if (lhs != null && lhs.Decl != null && QKeyValue.FindBoolAttribute(lhs.Decl.Attributes, "assumption")) + { + var rhs = Rhss[i] as NAryExpr; + if (rhs == null + || !(rhs.Fun is BinaryOperator) + || ((BinaryOperator)(rhs.Fun)).Op != BinaryOperator.Opcode.And + || !(rhs.Args[0] is IdentifierExpr) + || ((IdentifierExpr)(rhs.Args[0])).Name != lhs.Name) + { + rc.Error(tok, string.Format("RHS of assignment to assumption variable {0} must match expression \"{0} && \"", lhs.Name)); + } + else if (rc.HasVariableBeenAssigned(lhs.Decl.Name)) + { + rc.Error(tok, "assumption variable may not be assigned to more than once"); + } + else + { + rc.MarkVariableAsAssigned(lhs.Decl.Name); + } + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + + foreach (AssignLhs/*!*/ e in Lhss) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + foreach (Expr/*!*/ e in Rhss) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + + this.CheckAssignments(tc); + + for (int i = 0; i < Lhss.Count; ++i) { + Type ltype = Lhss[i].Type; + Type rtype = Rhss[i].Type; + if (ltype != null && rtype != null) { + // otherwise, there has already been an error when + // typechecking the lhs or rhs + if (!ltype.Unify(rtype)) + tc.Error(Lhss[i], + "mismatched types in assignment command (cannot assign {0} to {1})", + rtype, ltype); + } + } + } + + public override void AddAssignedVariables(List vars) { + + foreach (AssignLhs/*!*/ l in Lhss) { + Contract.Assert(l != null); + vars.Add(l.DeepAssignedVariable); + } + } + + // transform away the syntactic sugar of map assignments and + // determine an equivalent assignment in which all rhs are simple + // variables + public AssignCmd/*!*/ AsSimpleAssignCmd { + get { + Contract.Ensures(Contract.Result() != null); + + List/*!*/ newLhss = new List(); + List/*!*/ newRhss = new List(); + + for (int i = 0; i < Lhss.Count; ++i) { + IdentifierExpr/*!*/ newLhs; + Expr/*!*/ newRhs; + Lhss[i].AsSimpleAssignment(Rhss[i], out newLhs, out newRhs); + newLhss.Add(new SimpleAssignLhs(Token.NoToken, newLhs)); + newRhss.Add(newRhs); + } + + return new AssignCmd(Token.NoToken, newLhss, newRhss); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + + return visitor.VisitAssignCmd(this); + } + } + + // There are two different kinds of left-hand sides in assignments: + // simple variables (identifiers), or locations of a map + [ContractClass(typeof(AssignLhsContracts))] + public abstract class AssignLhs : Absy { + // The type of the lhs is determined during typechecking + public abstract Type Type { + get; + } + // Determine the variable that is actually assigned in this lhs + public abstract IdentifierExpr/*!*/ DeepAssignedIdentifier { + get; + } + public abstract Variable DeepAssignedVariable { + get; + } + + public AssignLhs(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + public abstract void Emit(TokenTextWriter/*!*/ stream); + + public abstract Expr/*!*/ AsExpr { + get; + } + + // transform away the syntactic sugar of map assignments and + // determine an equivalent simple assignment + internal abstract void AsSimpleAssignment(Expr/*!*/ rhs, + out IdentifierExpr/*!*/ simpleLhs, + out Expr/*!*/ simpleRhs); + } + [ContractClassFor(typeof(AssignLhs))] + public abstract class AssignLhsContracts : AssignLhs { + public AssignLhsContracts():base(null) + { + + }public override IdentifierExpr DeepAssignedIdentifier { + + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + public override Expr AsExpr { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + + } + internal override void AsSimpleAssignment(Expr rhs, out IdentifierExpr simpleLhs, out Expr simpleRhs) { + Contract.Requires(rhs != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); + + throw new NotImplementedException(); + } + } + + public class SimpleAssignLhs : AssignLhs { + public IdentifierExpr/*!*/ AssignedVariable; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(AssignedVariable != null); + } + + + public override Type Type { + get { + return AssignedVariable.Type; + } + } + + public override IdentifierExpr/*!*/ DeepAssignedIdentifier { + get { + Contract.Ensures(Contract.Result() != null); + return AssignedVariable; + } + } + + public override Variable DeepAssignedVariable { + get { + return AssignedVariable.Decl; + } + } + + public SimpleAssignLhs(IToken tok, IdentifierExpr assignedVariable) + : base(tok) { + Contract.Requires(assignedVariable != null); + Contract.Requires(tok != null); + AssignedVariable = assignedVariable; + } + public override void Resolve(ResolutionContext rc) { + + AssignedVariable.Resolve(rc); + } + public override void Typecheck(TypecheckingContext tc) { + + AssignedVariable.Typecheck(tc); + } + public override void Emit(TokenTextWriter stream) { + + AssignedVariable.Emit(stream); + } + public override Expr/*!*/ AsExpr { + get { + Contract.Ensures(Contract.Result() != null); + + return AssignedVariable; + } + } + internal override void AsSimpleAssignment(Expr rhs, + out IdentifierExpr/*!*/ simpleLhs, + out Expr/*!*/ simpleRhs) { + + + + simpleLhs = AssignedVariable; + simpleRhs = rhs; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + + + return visitor.VisitSimpleAssignLhs(this); + } + } + + // A map-assignment-lhs (m[t1, t2, ...] := ...) is quite similar to + // a map select expression, but it is cleaner to keep those two + // things separate + public class MapAssignLhs : AssignLhs { + public AssignLhs/*!*/ Map; + + public List/*!*/ Indexes; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Map != null); + Contract.Invariant(cce.NonNullElements(Indexes)); + } + + + // The instantiation of type parameters of the map that is + // determined during type checking. + public TypeParamInstantiation TypeParameters = null; + + private Type TypeAttr = null; + + public override Type Type { + get { + return TypeAttr; + } + } + + public override IdentifierExpr/*!*/ DeepAssignedIdentifier { + get { + Contract.Ensures(Contract.Result() != null); + + return Map.DeepAssignedIdentifier; + } + } + + public override Variable DeepAssignedVariable { + get { + return Map.DeepAssignedVariable; + } + } + + public MapAssignLhs(IToken tok, AssignLhs map, List/*!*/ indexes) + : base(tok) { + Contract.Requires(map != null); + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(indexes)); + + Map = map; + Indexes = indexes; + } + public override void Resolve(ResolutionContext rc) { + + Map.Resolve(rc); + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + e.Resolve(rc); + } + } + public override void Typecheck(TypecheckingContext tc) { + + Map.Typecheck(tc); + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + + // we use the same typechecking code as in MapSelect + List/*!*/ selectArgs = new List(); + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + selectArgs.Add(e); + } + TypeParamInstantiation/*!*/ tpInsts; + TypeAttr = + MapSelect.Typecheck(cce.NonNull(Map.Type), Map, + selectArgs, out tpInsts, tc, tok, "map assignment"); + TypeParameters = tpInsts; + } + public override void Emit(TokenTextWriter stream) { + + Map.Emit(stream); + stream.Write("["); + string/*!*/ sep = ""; + foreach (Expr/*!*/ e in Indexes) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + } + stream.Write("]"); + } + public override Expr/*!*/ AsExpr { + get { + Contract.Ensures(Contract.Result() != null); + + NAryExpr/*!*/ res = Expr.Select(Map.AsExpr, Indexes); + Contract.Assert(res != null); + res.TypeParameters = this.TypeParameters; + res.Type = this.Type; + return res; + } + } + internal override void AsSimpleAssignment(Expr rhs, + out IdentifierExpr/*!*/ simpleLhs, + out Expr/*!*/ simpleRhs) { //Contract.Requires(rhs != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleLhs) != null); + Contract.Ensures(Contract.ValueAtReturn(out simpleRhs) != null); + + NAryExpr/*!*/ newRhs = Expr.Store(Map.AsExpr, Indexes, rhs); + Contract.Assert(newRhs != null); + newRhs.TypeParameters = this.TypeParameters; + newRhs.Type = Map.Type; + Map.AsSimpleAssignment(newRhs, out simpleLhs, out simpleRhs); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitMapAssignLhs(this); + } + } + + /// + /// A StateCmd is like an imperative-let binding around a sequence of commands. + /// There is no user syntax for a StateCmd. Instead, a StateCmd is only used + /// temporarily during the desugaring phase inside the VC generator. + /// + public class StateCmd : Cmd { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._locals != null); + Contract.Invariant(this._cmds != null); + } + + private List _locals; + + public /*readonly, except for the StandardVisitor*/ List/*!*/ Locals { + get { + Contract.Ensures(Contract.Result>() != null); + return this._locals; + } + internal set { + Contract.Requires(value != null); + this._locals = value; + } + } + + private List _cmds; + + public /*readonly, except for the StandardVisitor*/ List/*!*/ Cmds { + get { + Contract.Ensures(Contract.Result>() != null); + return this._cmds; + } + set { + Contract.Requires(value != null); + this._cmds = value; + } + } + + public StateCmd(IToken tok, List/*!*/ locals, List/*!*/ cmds) + : base(tok) { + Contract.Requires(locals != null); + Contract.Requires(cmds != null); + Contract.Requires(tok != null); + this._locals = locals; + this._cmds = cmds; + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.PushVarContext(); + foreach (Variable/*!*/ v in Locals) { + Contract.Assert(v != null); + rc.AddVariable(v, false); + } + foreach (Cmd/*!*/ cmd in Cmds) { + Contract.Assert(cmd != null); + cmd.Resolve(rc); + } + rc.PopVarContext(); + } + + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + List/*!*/ vs = new List(); + foreach (Cmd/*!*/ cmd in this.Cmds) { + Contract.Assert(cmd != null); + cmd.AddAssignedVariables(vs); + } + System.Collections.Hashtable/*!*/ localsSet = new System.Collections.Hashtable(); + foreach (Variable/*!*/ local in this.Locals) { + Contract.Assert(local != null); + localsSet[local] = bool.TrueString; + } + foreach (Variable/*!*/ v in vs) { + Contract.Assert(v != null); + if (!localsSet.ContainsKey(v)) { + vars.Add(v); + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (Cmd/*!*/ cmd in Cmds) { + Contract.Assert(cmd != null); + cmd.Typecheck(tc); + } + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(this, level, "{"); + foreach (Variable/*!*/ v in Locals) { + Contract.Assert(v != null); + v.Emit(stream, level + 1); + } + foreach (Cmd/*!*/ c in Cmds) { + Contract.Assert(c != null); + c.Emit(stream, level + 1); + } + stream.WriteLine(level, "}"); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitStateCmd(this); + } + } + [ContractClass(typeof(SugaredCmdContracts))] + abstract public class SugaredCmd : Cmd { + private Cmd desugaring; // null until desugared + + public SugaredCmd(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + + public Cmd/*!*/ Desugaring { + get { + Contract.Ensures(Contract.Result() != null); + + if (desugaring == null) { + desugaring = ComputeDesugaring(); + } + return desugaring; + } + } + /// + /// This method invokes "visitor.Visit" on the desugaring, and then updates the + /// desugaring to the result thereof. The method's intended use is for subclasses + /// of StandardVisitor that need to also visit the desugaring. Note, since the + /// "desugaring" field is updated, this is not an appropriate method to be called + /// be a ReadOnlyVisitor; such visitors should instead just call + /// visitor.Visit(sugaredCmd.Desugaring). + /// + public void VisitDesugaring(StandardVisitor visitor) { + Contract.Requires(visitor != null && !(visitor is ReadOnlyVisitor)); + if (desugaring != null) { + desugaring = (Cmd)visitor.Visit(desugaring); + } + } + protected abstract Cmd/*!*/ ComputeDesugaring(); + + public void ExtendDesugaring(IEnumerable before, IEnumerable beforePreconditionCheck, IEnumerable after) + { + var desug = Desugaring; + var stCmd = desug as StateCmd; + if (stCmd != null) + { + stCmd.Cmds.InsertRange(0, before); + var idx = stCmd.Cmds.FindIndex(c => c is AssertCmd || c is HavocCmd || c is AssumeCmd); + if (idx < 0) + { + idx = 0; + } + stCmd.Cmds.InsertRange(idx, beforePreconditionCheck); + stCmd.Cmds.AddRange(after); + } + else if (desug != null) + { + var cmds = new List(before); + cmds.Add(desug); + cmds.AddRange(after); + desugaring = new StateCmd(Token.NoToken, new List(), cmds); + } + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + if (CommandLineOptions.Clo.PrintDesugarings && !stream.UseForComputingChecksums) { + stream.WriteLine(this, level, "/*** desugaring:"); + Desugaring.Emit(stream, level); + stream.WriteLine(level, "**** end desugaring */"); + } + } + } + [ContractClassFor(typeof(SugaredCmd))] + public abstract class SugaredCmdContracts : SugaredCmd { + public SugaredCmdContracts() :base(null){ + + } + protected override Cmd ComputeDesugaring() { + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + } + + public abstract class CallCommonality : SugaredCmd { + public QKeyValue Attributes; + + private bool isFree = false; + public bool IsFree { + get { + return isFree; + } + set { + isFree = value; + } + } + + private bool isAsync = false; + public bool IsAsync + { + get + { + return isAsync; + } + set + { + isAsync = value; + } + } + + protected CallCommonality(IToken tok, QKeyValue kv) + : base(tok) { + Contract.Requires(tok != null); + Attributes = kv; + } + + protected enum TempVarKind { + Formal, + Old, + Bound + } + + // We have to give the type explicitly, because the type of the formal "likeThisOne" can contain type variables + protected Variable CreateTemporaryVariable(List tempVars, Variable likeThisOne, Type ty, TempVarKind kind, ref int uniqueId) { + Contract.Requires(ty != null); + Contract.Requires(likeThisOne != null); + Contract.Requires(tempVars != null); + Contract.Ensures(Contract.Result() != null); + string/*!*/ tempNamePrefix; + switch (kind) { + case TempVarKind.Formal: + tempNamePrefix = "formal@"; + break; + case TempVarKind.Old: + tempNamePrefix = "old@"; + break; + case TempVarKind.Bound: + tempNamePrefix = "forall@"; + break; + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // unexpected kind + } + TypedIdent ti = likeThisOne.TypedIdent; + // KLM: uniqueId was messing up FixedPointVC for unknown reason. + // I reverted this change for FixedPointVC only. + int id = CommandLineOptions.Clo.FixedPointEngine != null ? UniqueId : (uniqueId++); + TypedIdent newTi = new TypedIdent(ti.tok, "call" + id + tempNamePrefix + ti.Name, ty); + Variable/*!*/ v; + if (kind == TempVarKind.Bound) { + v = new BoundVariable(likeThisOne.tok, newTi); + } else { + v = new LocalVariable(likeThisOne.tok, newTi); + tempVars.Add(v); + } + return v; + } + } + + public class ParCallCmd : CallCommonality, IPotentialErrorNode + { + public List CallCmds; + public ParCallCmd(IToken tok, List callCmds) + : base(tok, null) + { + this.CallCmds = callCmds; + } + public ParCallCmd(IToken tok, List callCmds, QKeyValue kv) + : base(tok, kv) + { + this.CallCmds = callCmds; + } + protected override Cmd ComputeDesugaring() + { + throw new NotImplementedException(); + } + private object errorData; + public object ErrorData + { + get + { + return errorData; + } + set + { + errorData = value; + } + } + public override void Resolve(ResolutionContext rc) + { + ResolveAttributes(Attributes, rc); + foreach (CallCmd callCmd in CallCmds) + { + callCmd.Resolve(rc); + } + HashSet parallelCallLhss = new HashSet(); + foreach (CallCmd callCmd in CallCmds) + { + foreach (IdentifierExpr ie in callCmd.Outs) + { + if (parallelCallLhss.Contains(ie.Decl)) + { + rc.Error(this, "left-hand side of parallel call command contains variable twice: {0}", ie.Name); + } + else + { + parallelCallLhss.Add(ie.Decl); + } + } + } + } + public override void Typecheck(TypecheckingContext tc) + { + TypecheckAttributes(Attributes, tc); + if (!CommandLineOptions.Clo.DoModSetAnalysis) + { + if (!tc.Yields) + { + tc.Error(this, "enclosing procedure of a parallel call must yield"); + } + foreach (CallCmd callCmd in CallCmds) + { + if (!QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "yields")) + { + tc.Error(callCmd, "target procedure of a parallel call must yield"); + } + } + } + foreach (CallCmd callCmd in CallCmds) + { + callCmd.Typecheck(tc); + } + } + public override void AddAssignedVariables(List vars) + { + foreach (CallCmd callCmd in CallCmds) + { + callCmd.AddAssignedVariables(vars); + } + } + public override Absy StdDispatch(StandardVisitor visitor) + { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitParCallCmd(this); + } + } + + public class CallCmd : CallCommonality, IPotentialErrorNode + { + public string/*!*/ callee { get; set; } + public Procedure Proc; + public LocalVariable AssignedAssumptionVariable; + + // Element of the following lists can be null, which means that + // the call happens with * as these parameters + public List/*!*/ Ins; + public List/*!*/ Outs; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(callee != null); + Contract.Invariant(Ins != null); + Contract.Invariant(Outs != null); + } + + //public Lattice.Element StateAfterCall; + + // The instantiation of type parameters that is determined during + // type checking + public TypeParamInstantiation TypeParameters = null; + + // TODO: convert to use generics + private object errorData; + public object ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + public CallCmd(IToken tok, string callee, List ins, List outs) + : base(tok, null) { + Contract.Requires(outs != null); + Contract.Requires(ins != null); + Contract.Requires(callee != null); + Contract.Requires(tok != null); + this.callee = callee; + this.Ins = ins; + this.Outs = outs; + } + public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv) + : base(tok, kv) { + Contract.Requires(outs != null); + Contract.Requires(ins != null); + Contract.Requires(callee != null); + Contract.Requires(tok != null); + this.callee = callee; + this.Ins = ins; + this.Outs = outs; + } + + public CallCmd(IToken tok, string callee, List ins, List outs, QKeyValue kv, bool IsAsync) + : base(tok, kv) + { + Contract.Requires(outs != null); + Contract.Requires(ins != null); + Contract.Requires(callee != null); + Contract.Requires(tok != null); + this.callee = callee; + this.Ins = ins; + this.Outs = outs; + this.IsAsync = IsAsync; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, ""); + if (IsFree) { + stream.Write("free "); + } + if (IsAsync) { + stream.Write("async "); + } + stream.Write("call "); + EmitAttributes(stream, Attributes); + string sep = ""; + if (Outs.Count > 0) { + foreach (Expr arg in Outs) { + stream.Write(sep); + sep = ", "; + if (arg == null) { + stream.Write("*"); + } else { + arg.Emit(stream); + } + } + stream.Write(" := "); + } + stream.Write(TokenTextWriter.SanitizeIdentifier(callee)); + stream.Write("("); + sep = ""; + foreach (Expr arg in Ins) { + stream.Write(sep); + sep = ", "; + if (arg == null) { + stream.Write("*"); + } else { + arg.Emit(stream); + } + } + stream.WriteLine(");"); + base.Emit(stream, level); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (Proc != null) { + // already resolved + return; + } + ResolveAttributes(Attributes, rc); + Proc = rc.LookUpProcedure(callee) as Procedure; + if (Proc == null) { + rc.Error(this, "call to undeclared procedure: {0}", callee); + } + foreach (Expr e in Ins) { + if (e != null) { + e.Resolve(rc); + } + } + HashSet actualOuts = new HashSet(); + foreach (IdentifierExpr ide in Outs) { + if (ide != null) { + ide.Resolve(rc); + if (ide.Decl != null) { + if (actualOuts.Contains(ide.Decl)) { + rc.Error(this, "left-hand side of call command contains variable twice: {0}", ide.Name); + } else { + actualOuts.Add(ide.Decl); + } + } + } + } + + if (Proc == null) + return; + + // first make sure that the right number of parameters is given + // (a similar check is in CheckArgumentTypes, but we are not + // able to call this method because it cannot cope with Ins/Outs + // that are null) + if (Ins.Count != Proc.InParams.Count) { + rc.Error(this.tok, + "wrong number of arguments in call to {0}: {1}", + callee, Ins.Count); + return; + } + if (Outs.Count != Proc.OutParams.Count) { + rc.Error(this.tok, + "wrong number of result variables in call to {0}: {1}", + callee, Outs.Count); + return; + } + if (IsAsync) { + if (Proc.OutParams.Count > 0) { + rc.Error(this.tok, "a procedure called asynchronously can have no output parameters"); + return; + } + } + + // Check that type parameters can be determined using the given + // actual i/o arguments. This is done already during resolution + // because CheckBoundVariableOccurrences needs a resolution + // context + List/*!*/ formalInTypes = new List(); + List/*!*/ formalOutTypes = new List(); + for (int i = 0; i < Ins.Count; ++i) + if (Ins[i] != null) + formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); + for (int i = 0; i < Outs.Count; ++i) + if (Outs[i] != null) + formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); + + // we need to bind the type parameters for this + // (this is expected by CheckBoundVariableOccurrences) + int previousTypeBinderState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in Proc.TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + Type.CheckBoundVariableOccurrences(Proc.TypeParameters, + formalInTypes, formalOutTypes, + this.tok, "types of given arguments", + rc); + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + } + + public override void AddAssignedVariables(List vars) { + if (this.IsAsync) + return; + foreach (IdentifierExpr e in Outs) { + if (e != null) { + vars.Add(e.Decl); + } + } + Contract.Assume(this.Proc != null); + foreach (IdentifierExpr/*!*/ e in this.Proc.Modifies) { + Contract.Assert(e != null); + vars.Add(e.Decl); + } + if (AssignedAssumptionVariable != null) + { + vars.Add(AssignedAssumptionVariable); + } + } + + public override void Typecheck(TypecheckingContext tc) + { + //Contract.Requires(tc != null); + Contract.Assume(this.Proc != null); // we assume the CallCmd has been successfully resolved before calling this Typecheck method + + TypecheckAttributes(Attributes, tc); + + // typecheck in-parameters + foreach (Expr e in Ins) + if (e != null) + e.Typecheck(tc); + foreach (Expr e in Outs) + if (e != null) + e.Typecheck(tc); + this.CheckAssignments(tc); + + List/*!*/ formalInTypes = new List(); + List/*!*/ formalOutTypes = new List(); + List/*!*/ actualIns = new List(); + List/*!*/ actualOuts = new List(); + for (int i = 0; i < Ins.Count; ++i) + { + if (Ins[i] != null) + { + formalInTypes.Add(cce.NonNull(Proc.InParams[i]).TypedIdent.Type); + actualIns.Add(Ins[i]); + } + } + for (int i = 0; i < Outs.Count; ++i) + { + if (Outs[i] != null) + { + formalOutTypes.Add(cce.NonNull(Proc.OutParams[i]).TypedIdent.Type); + actualOuts.Add(Outs[i]); + } + } + + // match actuals with formals + List/*!*/ actualTypeParams; + Type.CheckArgumentTypes(Proc.TypeParameters, + out actualTypeParams, + formalInTypes, actualIns, + formalOutTypes, actualOuts, + this.tok, + "call to " + callee, + tc); + Contract.Assert(cce.NonNullElements(actualTypeParams)); + TypeParameters = SimpleTypeParamInstantiation.From(Proc.TypeParameters, + actualTypeParams); + + if (!CommandLineOptions.Clo.DoModSetAnalysis && IsAsync) + { + if (!tc.Yields) + { + tc.Error(this, "enclosing procedure of an async call must yield"); + } + if (!QKeyValue.FindBoolAttribute(Proc.Attributes, "yields")) + { + tc.Error(this, "target procedure of an async call must yield"); + } + } + } + + private IDictionary/*!*/ TypeParamSubstitution() { + Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); + Contract.Assume(TypeParameters != null); + IDictionary/*!*/ res = new Dictionary(); + foreach (TypeVariable/*!*/ v in TypeParameters.FormalTypeParams) { + Contract.Assert(v != null); + res.Add(v, TypeParameters[v]); + } + return res; + } + + protected override Cmd ComputeDesugaring() { + Contract.Ensures(Contract.Result() != null); + + int uniqueId = 0; + List newBlockBody = new List(); + Dictionary substMap = new Dictionary(); + Dictionary substMapOld = new Dictionary(); + Dictionary substMapBound = new Dictionary(); + List/*!*/ tempVars = new List(); + + // proc P(ins) returns (outs) + // requires Pre + // //modifies frame + // ensures Post + // + // call aouts := P(ains) + + // ins : formal in parameters of procedure + // frame : a list of global variables from the modifies clause + // outs : formal out parameters of procedure + // ains : actual in arguments passed to call + // aouts : actual variables assigned to from call + // cins : new variables created just for this call, one per ains + // cframe : new variables created just for this call, to keep track of OLD values + // couts : new variables created just for this call, one per aouts + // WildcardVars : new variables created just for this call, one per null in ains + + #region Create cins; each one is an incarnation of the corresponding in parameter + List/*!*/ cins = new List(); + List wildcardVars = new List(); + Contract.Assume(this.Proc != null); + for (int i = 0; i < this.Proc.InParams.Count; ++i) { + Variable/*!*/ param = cce.NonNull(this.Proc.InParams[i]); + bool isWildcard = this.Ins[i] == null; + + Type/*!*/ actualType; + if (isWildcard) + actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); + else + // during type checking, we have ensured that the type of the actual + // parameter Ins[i] is correct, so we can use it here + actualType = cce.NonNull(cce.NonNull(Ins[i]).Type); + + Variable cin = CreateTemporaryVariable(tempVars, param, actualType, + TempVarKind.Formal, ref uniqueId); + cins.Add(cin); + IdentifierExpr ie = new IdentifierExpr(cin.tok, cin); + substMap.Add(param, ie); + if (isWildcard) { + cin = CreateTemporaryVariable(tempVars, param, + actualType, TempVarKind.Bound, ref uniqueId); + wildcardVars.Add(cin); + ie = new IdentifierExpr(cin.tok, cin); + } + substMapBound.Add(param, ie); + } + #endregion + #region call aouts := P(ains) becomes: (open outlining one level to see) + #region cins := ains (or havoc cin when ain is null) + for (int i = 0, n = this.Ins.Count; i < n; i++) { + IdentifierExpr/*!*/ cin_exp = new IdentifierExpr(cce.NonNull(cins[i]).tok, cce.NonNull(cins[i])); + Contract.Assert(cin_exp != null); + if (this.Ins[i] != null) { + AssignCmd assign = Cmd.SimpleAssign(Token.NoToken, cin_exp, cce.NonNull(this.Ins[i])); + newBlockBody.Add(assign); + } else { + List/*!*/ ies = new List(); + ies.Add(cin_exp); + HavocCmd havoc = new HavocCmd(Token.NoToken, ies); + newBlockBody.Add(havoc); + } + } + #endregion + + #region assert (exists wildcardVars :: Pre[ins := cins]) + Substitution s = Substituter.SubstitutionFromHashtable(substMapBound); + bool hasWildcard = (wildcardVars.Count != 0); + Expr preConjunction = null; + for (int i = 0; i < this.Proc.Requires.Count; i++) { + Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); + if (!req.Free && !IsFree) { + if (hasWildcard) { + Expr pre = Substituter.Apply(s, req.Condition); + if (preConjunction == null) { + preConjunction = pre; + } else { + preConjunction = Expr.And(preConjunction, pre); + } + } else { + Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); + reqCopy.Condition = Substituter.Apply(s, req.Condition); + AssertCmd/*!*/ a = new AssertRequiresCmd(this, reqCopy); + Contract.Assert(a != null); + if (Attributes != null) + { + // Inherit attributes of call. + var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); + attrCopy = Substituter.Apply(s, attrCopy); + a.Attributes = attrCopy; + } + a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced; + newBlockBody.Add(a); + } + } + else if (CommandLineOptions.Clo.StratifiedInlining > 0) + { + // inject free requires as assume statements at the call site + AssumeCmd/*!*/ a = new AssumeCmd(req.tok, Substituter.Apply(s, req.Condition)); + Contract.Assert(a != null); + newBlockBody.Add(a); + } + } + if (hasWildcard) { + if (preConjunction == null) { + preConjunction = Expr.True; + } + Expr/*!*/ expr = new ExistsExpr(tok, wildcardVars, preConjunction); + Contract.Assert(expr != null); + AssertCmd/*!*/ a = new AssertCmd(tok, expr); + Contract.Assert(a != null); + if (Attributes != null) + { + // Inherit attributes of call. + var attrCopy = (QKeyValue)cce.NonNull(Attributes.Clone()); + attrCopy = Substituter.Apply(s, attrCopy); + a.Attributes = attrCopy; + } + a.ErrorDataEnhanced = AssertCmd.GenerateBoundVarMiningStrategy(expr); + newBlockBody.Add(a); + } + #endregion + + #region assume Pre[ins := cins] with formal paramters + if (hasWildcard) { + s = Substituter.SubstitutionFromHashtable(substMap); + for (int i = 0; i < this.Proc.Requires.Count; i++) { + Requires/*!*/ req = cce.NonNull(this.Proc.Requires[i]); + if (!req.Free) { + Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); + reqCopy.Condition = Substituter.Apply(s, req.Condition); + AssumeCmd/*!*/ a = new AssumeCmd(tok, reqCopy.Condition); + Contract.Assert(a != null); + newBlockBody.Add(a); + } + } + } + #endregion + + #region cframe := frame (to hold onto frame values in case they are referred to in the postcondition) + List havocVarExprs = new List(); + + foreach (IdentifierExpr/*!*/ f in this.Proc.Modifies) { + Contract.Assert(f != null); + Contract.Assume(f.Decl != null); + Contract.Assert(f.Type != null); + Variable v = CreateTemporaryVariable(tempVars, f.Decl, f.Type, TempVarKind.Old, ref uniqueId); + IdentifierExpr v_exp = new IdentifierExpr(v.tok, v); + substMapOld.Add(f.Decl, v_exp); // this assumes no duplicates in this.Proc.Modifies + AssignCmd assign = Cmd.SimpleAssign(f.tok, v_exp, f); + newBlockBody.Add(assign); + + // fra + if (!havocVarExprs.Contains(f)) + havocVarExprs.Add(f); + } + #endregion + #region Create couts + List/*!*/ couts = new List(); + for (int i = 0; i < this.Proc.OutParams.Count; ++i) { + Variable/*!*/ param = cce.NonNull(this.Proc.OutParams[i]); + bool isWildcard = this.Outs[i] == null; + + Type/*!*/ actualType; + if (isWildcard) + actualType = param.TypedIdent.Type.Substitute(TypeParamSubstitution()); + else + // during type checking, we have ensured that the type of the actual + // out parameter Outs[i] is correct, so we can use it here + actualType = cce.NonNull(cce.NonNull(Outs[i]).Type); + + Variable cout = CreateTemporaryVariable(tempVars, param, actualType, + TempVarKind.Formal, ref uniqueId); + couts.Add(cout); + IdentifierExpr ie = new IdentifierExpr(cout.tok, cout); + substMap.Add(param, ie); + + if (!havocVarExprs.Contains(ie)) + havocVarExprs.Add(ie); + } + // add the where clauses, now that we have the entire substitution map + foreach (Variable/*!*/ param in this.Proc.OutParams) { + Contract.Assert(param != null); + Expr w = param.TypedIdent.WhereExpr; + if (w != null) { + IdentifierExpr ie = (IdentifierExpr/*!*/)cce.NonNull(substMap[param]); + Contract.Assert(ie.Decl != null); + ie.Decl.TypedIdent.WhereExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(substMap), w); + } + } + #endregion + + #region havoc frame, couts + // pass on this's token + HavocCmd hc = new HavocCmd(this.tok, havocVarExprs); + newBlockBody.Add(hc); + #endregion + + #region assume Post[ins, outs, old(frame) := cins, couts, cframe] + calleeSubstitution = Substituter.SubstitutionFromHashtable(substMap, true, Proc); + calleeSubstitutionOld = Substituter.SubstitutionFromHashtable(substMapOld, true, Proc); + foreach (Ensures/*!*/ e in this.Proc.Ensures) { + Contract.Assert(e != null); + Expr copy = Substituter.ApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, e.Condition); + AssumeCmd assume = new AssumeCmd(this.tok, copy); + #region stratified inlining support + if (QKeyValue.FindBoolAttribute(e.Attributes, "si_fcall")) + { + assume.Attributes = Attributes; + } + if (QKeyValue.FindBoolAttribute(e.Attributes, "candidate")) + { + assume.Attributes = new QKeyValue(Token.NoToken, "candidate", new List(), assume.Attributes); + assume.Attributes.AddParam(this.callee); + } + #endregion + newBlockBody.Add(assume); + } + #endregion + + #region aouts := couts + for (int i = 0, n = this.Outs.Count; i < n; i++) { + if (this.Outs[i] != null) { + Variable/*!*/ param_i = cce.NonNull(this.Proc.OutParams[i]); + Expr/*!*/ cout_exp = new IdentifierExpr(cce.NonNull(couts[i]).tok, cce.NonNull(couts[i])); + Contract.Assert(cout_exp != null); + AssignCmd assign = Cmd.SimpleAssign(param_i.tok, cce.NonNull(this.Outs[i]), cout_exp); + newBlockBody.Add(assign); + } + } + #endregion + #endregion + + return new StateCmd(this.tok, tempVars, newBlockBody); + } + + class NameEqualityComparer : EqualityComparer + { + public override bool Equals(IdentifierExpr x, IdentifierExpr y) + { + return x.Name.Equals(y.Name); + } + + public override int GetHashCode(IdentifierExpr obj) + { + return obj.Name.GetHashCode(); + } + } + + NameEqualityComparer comparer = new NameEqualityComparer(); + + public Substitution calleeSubstitution; + public Substitution calleeSubstitutionOld; + + public IEnumerable UnmodifiedBefore(Procedure oldProcedure) + { + Contract.Requires(oldProcedure != null); + + return Proc.Modifies.Except(oldProcedure.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); + } + + public IEnumerable ModifiedBefore(Procedure oldProcedure) + { + Contract.Requires(oldProcedure != null); + + return oldProcedure.Modifies.Except(Proc.Modifies, comparer).Select(e => new IdentifierExpr(Token.NoToken, e.Decl)); + } + + public Expr Postcondition(Procedure procedure, List modifies, Dictionary oldSubst, Program program, Func extract) + { + Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && modifies != null && oldSubst != null && program != null && extract != null); + + Substitution substOldCombined = v => { Expr s; if (oldSubst.TryGetValue(v, out s)) { return s; } return calleeSubstitutionOld(v); }; + + var clauses = procedure.Ensures.Select(e => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, substOldCombined, e.Condition, program)).Concat(modifies); + // TODO(wuestholz): Try extracting a function for each clause: + // return Conjunction(clauses.Select(c => extract(c))); + var conj = Expr.And(clauses, true); + return conj != null ? extract(conj) : conj; + } + + public Expr CheckedPrecondition(Procedure procedure, Program program, Func extract) + { + Contract.Requires(calleeSubstitution != null && calleeSubstitutionOld != null && program != null && extract != null); + + var clauses = procedure.Requires.Where(r => !r.Free).Select(r => Substituter.FunctionCallReresolvingApplyReplacingOldExprs(calleeSubstitution, calleeSubstitutionOld, r.Condition, program)); + // TODO(wuestholz): Try extracting a function for each clause: + // return Conjunction(clauses.Select(c => extract(c))); + var conj = Expr.And(clauses, true); + return conj != null ? extract(conj) : conj; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitCallCmd(this); + } + } + + public abstract class PredicateCmd : Cmd { + public QKeyValue Attributes; + public /*readonly--except in StandardVisitor*/ Expr/*!*/ Expr; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr != null); + } + + public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + Expr = expr; + } + public PredicateCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + Expr = expr; + Attributes = kv; + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Expr.Resolve(rc); + } + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + } + } + + public abstract class MiningStrategy { + // abstract class to bind all MiningStrategys, i.e., all types of enhanced error data + // types together + } + + public class ListOfMiningStrategies : MiningStrategy { + + private List/*!*/ _msList; + + public List/*!*/ msList + { + get + { + Contract.Ensures(Contract.Result>() != null); + return this._msList; + } + set + { + Contract.Requires(value != null); + this._msList = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._msList != null); + } + + public ListOfMiningStrategies(List l) { + Contract.Requires(l != null); + this._msList = l; + } + } + + public class EEDTemplate : MiningStrategy { + private string/*!*/ _reason; + public string/*!*/ reason + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._reason; + } + set + { + Contract.Requires(value != null); + this._reason = value; + } + } + + private List/*!*/ exprList; + public IEnumerable Expressions + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return this.exprList.AsReadOnly(); + } + set + { + Contract.Requires(cce.NonNullElements(value)); + this.exprList = new List(value); + } + } + + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._reason != null); + Contract.Invariant(cce.NonNullElements(this.exprList)); + } + + public EEDTemplate(string reason, List/*!*/ exprList) { + Contract.Requires(reason != null); + Contract.Requires(cce.NonNullElements(exprList)); + this._reason = reason; + this.exprList = exprList; + } + } + + public class AssertCmd : PredicateCmd, IPotentialErrorNode + { + public Expr OrigExpr; + public Dictionary IncarnationMap; + + Expr verifiedUnder; + public Expr VerifiedUnder + { + get + { + if (verifiedUnder != null) + { + return verifiedUnder; + } + verifiedUnder = QKeyValue.FindExprAttribute(Attributes, "verified_under"); + return verifiedUnder; + } + } + + public void MarkAsVerifiedUnder(Expr expr) + { + Attributes = new QKeyValue(tok, "verified_under", new List { expr }, Attributes); + verifiedUnder = expr; + } + + // TODO: convert to use generics + private object errorData; + public object ErrorData { + get { + return errorData; + } + set { + errorData = value; + } + } + + public string ErrorMessage { + get { + return QKeyValue.FindStringAttribute(Attributes, "msg"); + } + } + + private MiningStrategy errorDataEnhanced; + public MiningStrategy ErrorDataEnhanced { + get { + return errorDataEnhanced; + } + set { + errorDataEnhanced = value; + } + } + + public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); + } + + public AssertCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) + : base(tok, expr, kv) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + errorDataEnhanced = GenerateBoundVarMiningStrategy(expr); + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "assert "); + EmitAttributes(stream, Attributes); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + ResolveAttributes(Attributes, rc); + base.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + TypecheckAttributes(Attributes, tc); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "an asserted expression must be of type bool (got: {0})", Expr.Type); + } + } + + public static MiningStrategy GenerateBoundVarMiningStrategy(Expr expr) { + Contract.Requires(expr != null); + List l = new List(); + if (expr != null) { + l = GenerateBoundVarListForMining(expr, l); + } + return new ListOfMiningStrategies(l); + } + + public static List/*!*/ GenerateBoundVarListForMining(Expr expr, List l) { + Contract.Requires(l != null); + Contract.Requires(expr != null); + Contract.Ensures(Contract.Result>() != null); + + // go through the origExpr and identify all bound variables in the AST. + if (expr is LiteralExpr || expr is IdentifierExpr) { + //end recursion + } else if (expr is NAryExpr) { + NAryExpr e = (NAryExpr)expr; + foreach (Expr/*!*/ arg in e.Args) { + Contract.Assert(arg != null); + l = GenerateBoundVarListForMining(arg, l); + } + } else if (expr is OldExpr) { + OldExpr e = (OldExpr)expr; + l = GenerateBoundVarListForMining(e.Expr, l); + } else if (expr is QuantifierExpr) { + QuantifierExpr qe = (QuantifierExpr)expr; + List vs = qe.Dummies; + foreach (Variable/*!*/ x in vs) { + Contract.Assert(x != null); + string name = x.Name; + if (name.StartsWith("^")) { + name = name.Substring(1); + List exprList = new List(); + exprList.Add(new IdentifierExpr(Token.NoToken, x.ToString(), x.TypedIdent.Type)); + MiningStrategy eed = new EEDTemplate("The bound variable " + name + " has the value {0}.", exprList); + l.Add(eed); + } + } + l = GenerateBoundVarListForMining(qe.Body, l); + } + return l; + } + + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssertCmd(this); + } + } + + // An AssertCmd that is a loop invariant check before the loop iteration starts + public class LoopInitAssertCmd : AssertCmd { + public LoopInitAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + } + + // An AssertCmd that is a loop invariant check to maintain the invariant after iteration + public class LoopInvMaintainedAssertCmd : AssertCmd { + public LoopInvMaintainedAssertCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + } + + /// + /// An AssertCmd that is introduced in translation from the requires on a call. + /// + public class AssertRequiresCmd : AssertCmd { + public CallCmd/*!*/ Call; + public Requires/*!*/ Requires; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Call != null); + Contract.Invariant(Requires != null); + } + + + public AssertRequiresCmd(CallCmd/*!*/ call, Requires/*!*/ requires) + : base(call.tok, requires.Condition) { + Contract.Requires(call != null); + Contract.Requires(requires != null); + this.Call = call; + this.Requires = requires; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssertRequiresCmd(this); + } + } + + /// + /// An AssertCmd that is introduced in translation from an ensures + /// declaration. + /// + public class AssertEnsuresCmd : AssertCmd { + public Ensures/*!*/ Ensures; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Ensures != null); + } + + public AssertEnsuresCmd(Ensures/*!*/ ens) + : base(ens.tok, ens.Condition) { + Contract.Requires(ens != null); + this.Ensures = ens; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssertEnsuresCmd(this); + } + } + + public class AssumeCmd : PredicateCmd { + public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok, expr) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + public AssumeCmd(IToken/*!*/ tok, Expr/*!*/ expr, QKeyValue kv) + : base(tok, expr, kv) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "assume "); + EmitAttributes(stream, Attributes); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "an assumed expression must be of type bool (got: {0})", Expr.Type); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitAssumeCmd(this); + } + } + + public class ReturnExprCmd : ReturnCmd { + public Expr/*!*/ Expr; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr != null); + } + + public ReturnExprCmd(IToken/*!*/ tok, Expr/*!*/ expr) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + Expr = expr; + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "return "); + this.Expr.Emit(stream); + stream.WriteLine(";"); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Expr.Typecheck(tc); + Contract.Assert(Expr.Type != null); // follows from Expr.Typecheck postcondition + if (!Expr.Type.Unify(Type.Bool)) { + tc.Error(this, "a return expression must be of type bool (got: {0})", Expr.Type); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Expr.Resolve(rc); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitReturnExprCmd(this); + } + } + + public class HavocCmd : Cmd { + private List/*!*/ _vars; + + public List/*!*/ Vars { + get { + Contract.Ensures(Contract.Result>() != null); + return this._vars; + } + set { + Contract.Requires(value != null); + this._vars = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._vars != null); + } + + public HavocCmd(IToken/*!*/ tok, List/*!*/ vars) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(vars != null); + this._vars = vars; + } + + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.Write(this, level, "havoc "); + Vars.Emit(stream, true); + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + foreach (IdentifierExpr/*!*/ ide in Vars) { + Contract.Assert(ide != null); + ide.Resolve(rc); + } + } + public override void AddAssignedVariables(List vars) { + //Contract.Requires(vars != null); + foreach (IdentifierExpr/*!*/ e in this.Vars) { + Contract.Assert(e != null); + vars.Add(e.Decl); + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (IdentifierExpr ie in Vars) + { + ie.Typecheck(tc); + } + this.CheckAssignments(tc); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitHavocCmd(this); + } + } + + //--------------------------------------------------------------------- + // Transfer commands + [ContractClass(typeof(TransferCmdContracts))] + public abstract class TransferCmd : Absy { + internal TransferCmd(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + public abstract void Emit(TokenTextWriter/*!*/ stream, int level); + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + // nothing to typecheck + } + + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false , /*pretty=*/ false)) { + this.Emit(stream, 0); + } + return buffer.ToString(); + } + } + [ContractClassFor(typeof(TransferCmd))] + public abstract class TransferCmdContracts : TransferCmd { + public TransferCmdContracts() :base(null){ + + } + public override void Emit(TokenTextWriter stream, int level) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + } + + public class ReturnCmd : TransferCmd { + public ReturnCmd(IToken/*!*/ tok) + : base(tok) { + Contract.Requires(tok != null); + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + stream.WriteLine(this, level, "return;"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + // nothing to resolve + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitReturnCmd(this); + } + } + + public class GotoCmd : TransferCmd { + [Rep] + public List labelNames; + [Rep] + public List labelTargets; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(labelNames == null || labelTargets == null || labelNames.Count == labelTargets.Count); + } + + [NotDelayed] + public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(labelSeq != null); + this.labelNames = labelSeq; + } + public GotoCmd(IToken/*!*/ tok, List/*!*/ labelSeq, List/*!*/ blockSeq) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(labelSeq != null); + Contract.Requires(blockSeq != null); + Debug.Assert(labelSeq.Count == blockSeq.Count); + for (int i = 0; i < labelSeq.Count; i++) { + Debug.Assert(Equals(labelSeq[i], cce.NonNull(blockSeq[i]).Label)); + } + + this.labelNames = labelSeq; + this.labelTargets = blockSeq; + } + public GotoCmd(IToken/*!*/ tok, List/*!*/ blockSeq) + : base(tok) { //requires (blockSeq[i] != null ==> blockSeq[i].Label != null); + Contract.Requires(tok != null); + Contract.Requires(blockSeq != null); + List labelSeq = new List(); + for (int i = 0; i < blockSeq.Count; i++) + labelSeq.Add(cce.NonNull(blockSeq[i]).Label); + this.labelNames = labelSeq; + this.labelTargets = blockSeq; + } + public void AddTarget(Block b) { + Contract.Requires(b != null); + Contract.Requires(b.Label != null); + Contract.Requires(this.labelTargets != null); + Contract.Requires(this.labelNames != null); + this.labelTargets.Add(b); + this.labelNames.Add(b.Label); + } + public override void Emit(TokenTextWriter stream, int level) { + //Contract.Requires(stream != null); + Contract.Assume(this.labelNames != null); + stream.Write(this, level, "goto "); + if (CommandLineOptions.Clo.PrintWithUniqueASTIds) { + if (labelTargets == null) { + string sep = ""; + foreach (string name in labelNames) { + stream.Write("{0}{1}^^{2}", sep, "NoDecl", name); + sep = ", "; + } + } else { + string sep = ""; + foreach (Block/*!*/ b in labelTargets) { + Contract.Assert(b != null); + stream.Write("{0}h{1}^^{2}", sep, b.GetHashCode(), b.Label); + sep = ", "; + } + } + } else { + labelNames.Emit(stream); + } + stream.WriteLine(";"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(labelTargets != null); + if (labelTargets != null) { + // already resolved + return; + } + Contract.Assume(this.labelNames != null); + labelTargets = new List(); + foreach (string/*!*/ lbl in labelNames) { + Contract.Assert(lbl != null); + Block b = rc.LookUpBlock(lbl); + if (b == null) { + rc.Error(this, "goto to unknown block: {0}", lbl); + } else { + labelTargets.Add(b); + } + } + Debug.Assert(rc.ErrorCount > 0 || labelTargets.Count == labelNames.Count); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitGotoCmd(this); + } + } +} diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index c816d7f2..7ffd5f7f 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1,3257 +1,3257 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - using System.Linq; - using Microsoft.Basetypes; - - using Set = GSet; // not that the set used is not a set of Variable only, as it also contains TypeVariables - - - //--------------------------------------------------------------------- - // Expressions - // - // For expressions, we override the Equals and GetHashCode method to - // implement structural equality. Note this is not logical equivalence - // and is not modulo alpha-renaming. - //--------------------------------------------------------------------- - - - [ContractClass(typeof(ExprContracts))] - public abstract class Expr : Absy { - public Expr(IToken/*!*/ tok, bool immutable) - : base(tok) { - Contract.Requires(tok != null); - this.Immutable = immutable; - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - Emit(stream, 0, false); - } - - /// - /// If true the client is making a promise that this Expr will be - /// treated immutably (i.e. once constructed it is never changed). - /// This is currently not enforced but it should be! - /// - /// This allows the Expr's hash code to be cached making calls to - /// GetHashCode() very cheap. - /// - /// true if immutable; otherwise, false. - public bool Immutable { - get; - private set; - } - - /// - /// Computes the hash code of this Expr skipping any cache. - /// - /// Sub classes should place their implementation of computing their hashcode - /// here (making sure to call GetHashCode() not ComputeHashCode() on Expr for performance reasons) - /// and have GetHashCode() use a cached result from ComputeHashCode() if the - /// Expr was constructed to be immutable. - /// - /// The hash code. - public abstract int ComputeHashCode(); - protected int CachedHashCode = 0; - - public abstract void Emit(TokenTextWriter/*!*/ wr, int contextBindingStrength, bool fragileContext); - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false, /*pretty=*/ false)) { - this.Emit(stream, 0, false); - } - return buffer.ToString(); - } - - /// - /// Add to "freeVars" the free variables in the expression. - /// - public abstract void ComputeFreeVariables(Set /*Variable*//*!*/ freeVars); - - /// - /// Filled in by the Typecheck method. A value of "null" means a succeeding - /// call to Typecheck has not taken place (that is, either Typecheck hasn't - /// been called or Typecheck encountered an error in the expression to be - /// typechecked). - /// - private Type _Type = null; - public Type Type { - get { - return _Type; - } - set { - if (_Type == null) { - // Expr has never been type checked so always allow this - _Type = value; - } else { - if (Immutable && !_Type.Equals(value)) - throw new InvalidOperationException("Cannot change the Type of an Immutable Expr"); - - // Once the Type has been set (i.e. no longer null) we never change the reference - // if this Expr is immutable, even if the Type is equivalent (i.e. _Type.Equals(newType)) - if (!Immutable) - _Type = value; - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Contract.Ensures(Type != null); - // This body is added only because C# insists on it. It should really be left out, as if TypeCheck still were abstract. - // The reason for mentioning the method here at all is to give TypeCheck a postcondition for all expressions. - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - - /// - /// Returns the type of the expression, supposing that all its subexpressions are well typed. - /// - public abstract Type/*!*/ ShallowType { - get; - } - - // Handy syntactic sugar follows: - - public static NAryExpr Unary(IToken x, UnaryOperator.Opcode op, Expr e1) { - Contract.Requires(e1 != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - return new NAryExpr(x, new UnaryOperator(x, op), new List { e1 }); - } - - public static NAryExpr Binary(IToken x, BinaryOperator.Opcode op, Expr e0, Expr e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - return new NAryExpr(x, new BinaryOperator(x, op), new List { e0, e1 }); - } - - public static NAryExpr Binary(BinaryOperator.Opcode op, Expr e0, Expr e1) { - Contract.Requires(e1 != null); - Contract.Requires(e0 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(Token.NoToken, op, e0, e1); - } - - public static NAryExpr Eq(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Eq, e1, e2); - } - public static NAryExpr Neq(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Neq, e1, e2); - } - public static NAryExpr Le(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Le, e1, e2); - } - public static NAryExpr Ge(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Ge, e1, e2); - } - public static NAryExpr Lt(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Lt, e1, e2); - } - public static NAryExpr Gt(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Gt, e1, e2); - } - public static Expr And(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - if (e1 == true_) { - return e2; - } else if (e2 == true_) { - return e1; - } else if (e1 == false_ || e2 == false_) { - return false_; - } else { - var res = Binary(BinaryOperator.Opcode.And, e1, e2); - res.Type = Microsoft.Boogie.Type.Bool; - res.TypeParameters = SimpleTypeParamInstantiation.EMPTY; - return res; - } - } - public static Expr Or(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - if (e1 == false_) { - return e2; - } else if (e2 == false_) { - return e1; - } else if (e1 == true_ || e2 == true_) { - return true_; - } else { - return Binary(BinaryOperator.Opcode.Or, e1, e2); - } - } - public static Expr Not(Expr e1) { - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - NAryExpr nary = e1 as NAryExpr; - - if (e1 == true_) { - return false_; - } else if (e1 == false_) { - return true_; - } else if (nary != null) { - if (nary.Fun is UnaryOperator) { - UnaryOperator op = (UnaryOperator)nary.Fun; - if (op.Op == UnaryOperator.Opcode.Not) { - return cce.NonNull(nary.Args[0]); - } - } else if (nary.Fun is BinaryOperator) { - BinaryOperator op = (BinaryOperator)nary.Fun; - Expr arg0 = cce.NonNull(nary.Args[0]); - Expr arg1 = cce.NonNull(nary.Args[1]); - if (op.Op == BinaryOperator.Opcode.Eq) { - return Neq(arg0, arg1); - } else if (op.Op == BinaryOperator.Opcode.Neq) { - return Eq(arg0, arg1); - } else if (op.Op == BinaryOperator.Opcode.Lt) { - return Le(arg1, arg0); - } else if (op.Op == BinaryOperator.Opcode.Le) { - return Lt(arg1, arg0); - } else if (op.Op == BinaryOperator.Opcode.Ge) { - return Gt(arg1, arg0); - } else if (op.Op == BinaryOperator.Opcode.Gt) { - return Ge(arg1, arg0); - } - } - } - - return Unary(Token.NoToken, UnaryOperator.Opcode.Not, e1); - } - - public static Expr Neg(Expr e1) { - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Unary(Token.NoToken, UnaryOperator.Opcode.Neg, e1); - } - - public static NAryExpr Imp(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Imp, e1, e2); - } - public static NAryExpr Iff(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Iff, e1, e2); - } - public static NAryExpr Add(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Add, e1, e2); - } - public static NAryExpr Sub(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Sub, e1, e2); - } - public static NAryExpr Mul(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Mul, e1, e2); - } - public static NAryExpr Div(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Div, e1, e2); - } - public static NAryExpr Mod(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Mod, e1, e2); - } - public static NAryExpr RealDiv(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.RealDiv, e1, e2); - } - public static NAryExpr Pow(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Pow, e1, e2); - } - public static NAryExpr Subtype(Expr e1, Expr e2) { - Contract.Requires(e2 != null); - Contract.Requires(e1 != null); - Contract.Ensures(Contract.Result() != null); - return Binary(BinaryOperator.Opcode.Subtype, e1, e2); - } - - public static IdentifierExpr Ident(string name, Type type) { - Contract.Requires(type != null); - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); - return new IdentifierExpr(Token.NoToken, name, type); - } - - public static IdentifierExpr Ident(Variable decl) { - Contract.Requires(decl != null); - Contract.Ensures(Contract.Result() != null); - IdentifierExpr result = new IdentifierExpr(Token.NoToken, decl); - return result; - } - - public static LiteralExpr Literal(bool value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - public static LiteralExpr Literal(int value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, BigNum.FromInt(value)); - } - public static LiteralExpr Literal(BigNum value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - public static LiteralExpr Literal(BigDec value) { - Contract.Ensures(Contract.Result() != null); - return new LiteralExpr(Token.NoToken, value); - } - - private static LiteralExpr/*!*/ true_ = Literal(true); - public static LiteralExpr/*!*/ True { - get { - Contract.Ensures(Contract.Result() != null); - return true_; - } - } - - private static LiteralExpr/*!*/ false_ = Literal(false); - public static LiteralExpr/*!*/ False { - get { - Contract.Ensures(Contract.Result() != null); - return false_; - } - } - - - public static NAryExpr Select(Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Ensures(Contract.Result() != null); - return SelectTok(Token.NoToken, map, args); - } - - public static NAryExpr Select(Expr map, List/*!*/ args) { - Contract.Requires(map != null); - Contract.Requires(cce.NonNullElements(args)); - Contract.Ensures(Contract.Result() != null); - return Select(map, args.ToArray()); - } - - // use a different name for this variant of the method - // (-> some bug prevents overloading in this case) - public static NAryExpr SelectTok(IToken x, Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ allArgs = new List(); - allArgs.Add(map); - foreach (Expr/*!*/ a in args) { - Contract.Assert(a != null); - allArgs.Add(a); - } - return new NAryExpr(x, new MapSelect(Token.NoToken, args.Length), allArgs); - } - - public static NAryExpr Store(Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Ensures(Contract.Result() != null); - return StoreTok(Token.NoToken, map, args); - } - - public static NAryExpr Store(Expr map, List/*!*/ indexes, Expr rhs) { - Contract.Requires(rhs != null); - Contract.Requires(map != null); - Contract.Requires(cce.NonNullElements(indexes)); - Contract.Ensures(Contract.Result() != null); - Expr[]/*!*/ allArgs = new Expr[indexes.Count + 1]; - for (int i = 0; i < indexes.Count; ++i) - allArgs[i] = indexes[i]; - allArgs[indexes.Count] = rhs; - return Store(map, allArgs); - } - - // use a different name for this variant of the method - // (-> some bug prevents overloading in this case) - public static NAryExpr/*!*/ StoreTok(IToken x, Expr map, params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(map != null); - Contract.Requires(x != null); - Contract.Requires(args.Length > 0); // zero or more indices, plus the value - Contract.Ensures(Contract.Result() != null); - - List/*!*/ allArgs = new List(); - allArgs.Add(map); - foreach (Expr/*!*/ a in args) { - Contract.Assert(a != null); - allArgs.Add(a); - } - return new NAryExpr(x, new MapStore(Token.NoToken, args.Length - 1), allArgs); - } - - public static NAryExpr CoerceType(IToken x, Expr subexpr, Type type) { - Contract.Requires(type != null); - Contract.Requires(subexpr != null); - Contract.Requires(x != null); - Contract.Ensures(Contract.Result() != null); - List/*!*/ args = new List(); - args.Add(subexpr); - return new NAryExpr(x, new TypeCoercion(x, type), args); - } - - public static Expr BinaryTreeAnd(List terms) - { - return BinaryTreeAnd(terms, 0, terms.Count - 1); - } - - private static Expr BinaryTreeAnd(List terms, int start, int end) - { - if (start > end) - return Expr.True; - if (start == end) - return terms[start]; - if (start + 1 == end) - return Expr.And(terms[start], terms[start + 1]); - var mid = (start + end) / 2; - return Expr.And(BinaryTreeAnd(terms, start, mid), BinaryTreeAnd(terms, mid + 1, end)); - } - - public static Expr And(IEnumerable conjuncts, bool returnNullIfEmpty = false) - { - Expr result = null; - foreach (var c in conjuncts) - { - if (result != null) - { - result = LiteralExpr.And(result, c); - result.Type = Type.Bool; - } - else - { - result = c; - result.Type = Type.Bool; - } - } - if (result == null && !returnNullIfEmpty) - { - result = Expr.True; - } - return result; - } - } - [ContractClassFor(typeof(Expr))] - public abstract class ExprContracts : Expr { - public ExprContracts() :base(null, /*immutable=*/ false){ - - } - public override void Emit(TokenTextWriter wr, int contextBindingStrength, bool fragileContext) { - Contract.Requires(wr != null); - throw new NotImplementedException(); - } - public override void ComputeFreeVariables(Set freeVars) { - Contract.Requires(freeVars != null); - throw new NotImplementedException(); - } - public override Type ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - } - } - - public class LiteralExpr : Expr { - public readonly object/*!*/ Val; // false, true, a BigNum, a BigDec, or a BvConst - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Val != null); - } - - /// - /// Creates a literal expression for the boolean value "b". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, bool b, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Val = b; - Type = Type.Bool; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the integer value "v". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, BigNum v, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Val = v; - Type = Type.Int; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the real value "v". - /// - /// - /// - public LiteralExpr(IToken/*!*/ tok, BigDec v, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Val = v; - Type = Type.Real; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a literal expression for the bitvector value "v". - /// - public LiteralExpr(IToken/*!*/ tok, BigNum v, int b, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(0 <= b); - Val = new BvConst(v, b); - Type = Type.GetBvType(b); - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is LiteralExpr)) - return false; - - LiteralExpr other = (LiteralExpr)obj; - return object.Equals(this.Val, other.Val); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - return this.Val.GetHashCode(); - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - if (this.Val is bool) { - stream.Write((bool)this.Val ? "true" : "false"); // correct capitalization - } else { - stream.Write(cce.NonNull(this.Val.ToString())); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - // nothing to resolve - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - // no free variables to add - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - this.Type = ShallowType; - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - if (Val is bool) { - return Type.Bool; - } else if (Val is BigNum) { - return Type.Int; - } else if (Val is BigDec) { - return Type.Real; - } else if (Val is BvConst) { - return Type.GetBvType(((BvConst)Val).Bits); - } else { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // like, where did this value come from?! - } - } - } - - public bool IsFalse { - get { - return Val is bool && ((bool)Val) == false; - } - } - public bool IsTrue { - get { - return Val is bool && ((bool)Val) == true; - } - } - - // should be eliminated after converting everything to BigNums - private int asInt { - get { - return asBigNum.ToIntSafe; - } - } - - public bool isBigNum { - get { - return Val is BigNum; - } - } - - public BigNum asBigNum { - get { - Contract.Assert(isBigNum); - return (BigNum)cce.NonNull(Val); - } - } - - public bool isBigDec { - get { - return Val is BigDec; - } - } - - public BigDec asBigDec { - get { - Contract.Assert(isBigDec); - return (BigDec)cce.NonNull(Val); - } - } - - public bool isBool { - get { - return Val is bool; - } - } - - public bool asBool { - get { - Contract.Assert(isBool); - return (bool)cce.NonNull(Val); - } - } - - public bool isBvConst { - get { - return Val is BvConst; - } - } - - public BvConst asBvConst { - get { - Contract.Assert(isBvConst); - return (BvConst)cce.NonNull(Val); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitLiteralExpr(this); - } - } - - public class BvConst { - public readonly BigNum Value; - public readonly int Bits; - - public BvConst(BigNum v, int b) { - Contract.Assert(v.Signum >= 0); - Value = v; - Bits = b; - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return Value + "bv" + Bits; - } - - [Pure] - public string ToReadableString() { - Contract.Ensures(Contract.Result() != null); - if (Value > BigNum.FromInt(10000)) { - string val = cce.NonNull(Value.ToString("x")); - int pos = val.Length % 4; - string res = "0x" + val.Substring(0, pos); - Contract.Assert(res != null); - while (pos < val.Length) { - res += "." + val.Substring(pos, 4); - pos += 4; - } - return res + ".bv" + Bits; - } else - return ToString(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - BvConst other = obj as BvConst; - if (other == null) - return false; - - return Bits == other.Bits && Value == other.Value; - } - - [Pure] - public override int GetHashCode() { - unchecked { - return Value.GetHashCode() ^ Bits; - } - } - } - - public class IdentifierExpr : Expr { - private string _Name; - public string Name { // identifier symbol - get { - return _Name; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Name on Immutable Expr"); - - _Name = value; - } - } - private Variable _Decl; - public Variable Decl { // identifier declaration - get { - return _Decl; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Decl on Immutable Expr"); - - _Decl = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - } - - - /// - /// Creates an unresolved identifier expression. This constructor is intended to be called - /// only from within the parser; for use inside the translation, use another constructor, which - /// specifies the type of the expression. - /// - /// - /// - internal IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - _Name = name; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - /// - /// Creates an unresolved identifier expression. - /// - /// - /// - /// - public IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(name != null); - Contract.Requires(type != null); - _Name = name; - Type = type; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - /// - /// Creates a resolved identifier expression. - /// - /// - /// - public IdentifierExpr(IToken/*!*/ tok, Variable/*!*/ d, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(d != null); - _Name = cce.NonNull(d.Name); - _Decl = d; - Type = d.TypedIdent.Type; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is IdentifierExpr)) - return false; - - IdentifierExpr other = (IdentifierExpr)obj; - return object.Equals(this.Name, other.Name) && object.Equals(this.Decl, other.Decl); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.Name == null ? 0 : this.Name.GetHashCode(); - h ^= this.Decl == null ? 0 : this.Decl.GetHashCode(); - return h; - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - if (CommandLineOptions.Clo.PrintWithUniqueASTIds && !stream.UseForComputingChecksums) { - stream.Write("{0}^^", this.Decl == null ? "NoDecl" : "h" + this.Decl.GetHashCode()); - } - stream.Write(this, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (Decl != null) { - // already resolved, but re-resolve type just in case it came from an unresolved type - if (Type != null) { - Type = Type.ResolveType(rc); - } - return; - } - Decl = rc.LookUpVariable(Name); - if (Decl == null) { - rc.Error(this, "undeclared identifier: {0}", Name); - } else if (rc.StateMode == ResolutionContext.State.StateLess && Decl is GlobalVariable) { - rc.Error(this, "cannot refer to a global variable in this context: {0}", Name); - } - if (Type != null) { - Type = Type.ResolveType(rc); - } - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - Contract.Assume(this.Decl != null); - freeVars.Add(Decl); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - if (this.Decl != null) { - // sanity check - if (Type != null && !Type.Equals(Decl.TypedIdent.Type)) { - tc.Error(this, "internal error, shallow-type assignment was done incorrectly, {0}:{1} != {2}", - Name, Type, Decl.TypedIdent.Type); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - } - Type = Decl.TypedIdent.Type; - } - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - Contract.Assert(Type != null); - return Type; - } - } - - public sealed class ConstantFunApp { - private IdentifierExpr/*!*/ identifierExpr; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(identifierExpr != null); - Contract.Invariant(emptyArgs != null); - } - - public IdentifierExpr/*!*/ IdentifierExpr { - get { - Contract.Requires(IdentifierExpr != null); - return identifierExpr; - } - } - - private static IList/*!*/ emptyArgs = ArrayList.ReadOnly(cce.NonNull((IList/*!*/)new ArrayList())); - public IList/*!*/ Arguments { - get { - Contract.Ensures(Contract.Result() != null); - return emptyArgs; - } - } - - public ConstantFunApp(IdentifierExpr ie, Constant c) { - Contract.Requires(c != null); - Contract.Requires(ie != null); - this.identifierExpr = ie; - } - - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitIdentifierExpr(this); - } - } - - public class OldExpr : Expr - { - private Expr _Expr; - public Expr/*!*/ Expr { - get { - return _Expr; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Expr of an Immutable OldExpr"); - - _Expr = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Expr != null); - } - - public OldExpr(IToken/*!*/ tok, Expr/*!*/ expr, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(expr != null); - _Expr = expr; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is OldExpr)) - return false; - - OldExpr other = (OldExpr)obj; - return object.Equals(this.Expr, other.Expr); - } - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode (); - } - public override int ComputeHashCode() { - // FIXME: This is wrong, it's as if the OldExpr node isn't there at all - return this.Expr == null ? 0 : this.Expr.GetHashCode(); - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.Write(this, "old("); - this.Expr.Emit(stream); - stream.Write(")"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (rc.StateMode != ResolutionContext.State.Two) { - rc.Error(this, "old expressions allowed only in two-state contexts"); - } - Expr.Resolve(rc); - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - Expr.ComputeFreeVariables(freeVars); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Expr.Typecheck(tc); - Type = Expr.Type; - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Expr.ShallowType; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitOldExpr(this); - } - } - [ContractClass(typeof(IAppliableVisitorContracts<>))] - public interface IAppliableVisitor { - T Visit(UnaryOperator/*!*/ unaryOperator); - T Visit(BinaryOperator/*!*/ binaryOperator); - T Visit(FunctionCall/*!*/ functionCall); - T Visit(MapSelect/*!*/ mapSelect); - T Visit(MapStore/*!*/ mapStore); - T Visit(TypeCoercion/*!*/ typeCoercion); - T Visit(ArithmeticCoercion/*!*/ arithCoercion); - T Visit(IfThenElse/*!*/ ifThenElse); - } - [ContractClassFor(typeof(IAppliableVisitor<>))] - public abstract class IAppliableVisitorContracts : IAppliableVisitor { - - #region IAppliableVisitor Members - - public T Visit(UnaryOperator unaryOperator) { - Contract.Requires(unaryOperator != null); - throw new NotImplementedException(); - } - - public T Visit(BinaryOperator binaryOperator) { - Contract.Requires(binaryOperator != null); - throw new NotImplementedException(); - } - - public T Visit(FunctionCall functionCall) { - Contract.Requires(functionCall != null); - throw new NotImplementedException(); - } - - public T Visit(MapSelect mapSelect) { - Contract.Requires(mapSelect != null); - throw new NotImplementedException(); - } - - public T Visit(MapStore mapStore) { - Contract.Requires(mapStore != null); - throw new NotImplementedException(); - } - - public T Visit(TypeCoercion typeCoercion) { - Contract.Requires(typeCoercion != null); - throw new NotImplementedException(); - } - - public T Visit(ArithmeticCoercion arithCoercion) { - Contract.Requires(arithCoercion != null); - throw new NotImplementedException(); - } - - public T Visit(IfThenElse ifThenElse) { - Contract.Requires(ifThenElse != null); - throw new NotImplementedException(); - } - - #endregion - } - - [ContractClass(typeof(IAppliableContracts))] - public interface IAppliable { - string/*!*/ FunctionName { - get; - } - - /// - /// Emits to "stream" the operator applied to the given arguments. - /// The length of "args" can be anything that the parser allows for this appliable operator - /// (but can be nothing else). - /// - /// - /// - /// - /// - void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext); - - void Resolve(ResolutionContext/*!*/ rc, Expr/*!*/ subjectForErrorReporting); - - /// - /// Requires the object to have been properly resolved. - /// - int ArgumentCount { - get; - } - - /// - /// Typechecks the arguments "args" for the Appliable. If the arguments are - /// appropriate, returns the result type; otherwise returns null. - /// As result of the type checking, the values of type parameters of the - /// appliable can be returned (which are then stored in the NAryExpr and later - /// also used in the VCExprAST). - /// Requires the object to have been successfully resolved. - /// Requires args.Length == ArgumentCount. - /// Requires all elements of "args" to have a non-null Type field. - /// - /// - /// - Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, TypecheckingContext/*!*/ tc); - - // Contract.Requires( Microsoft.SpecSharp.Collections.Reductions.Forall{Expr! arg in args; arg.Type != null}); - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - Type/*!*/ ShallowType(IList/*!*/ args); - - T Dispatch(IAppliableVisitor/*!*/ visitor); - } - [ContractClassFor(typeof(IAppliable))] - abstract class IAppliableContracts : IAppliable { - - #region IAppliable Members - - public string FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - Contract.Requires(args != null); - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - Contract.Requires(rc != null); - Contract.Requires(subjectForErrorReporting != null); - throw new NotImplementedException(); - } - - public int ArgumentCount { - get { - throw new NotImplementedException(); - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - Contract.Requires(args != null); - Contract.Requires(tc != null); - Contract.Ensures(Contract.ValueAtReturn(out args) != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(args.Count == Contract.OldValue(args.Count)); - throw new NotImplementedException(); - } - - public Type ShallowType(IList args) { - Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - - public T Dispatch(IAppliableVisitor visitor) { - Contract.Requires(visitor != null); - throw new NotImplementedException(); - } - - #endregion - } - - - [ContractClass(typeof(IOverloadedAppliableContracts))] - public interface IOverloadedAppliable { - void ResolveOverloading(NAryExpr/*!*/ expr); - bool DoNotResolveOverloading { get; set; } - } - [ContractClassFor(typeof(IOverloadedAppliable))] - public abstract class IOverloadedAppliableContracts : IOverloadedAppliable { - - #region IOverloadedAppliable Members - - void IOverloadedAppliable.ResolveOverloading(NAryExpr expr) { - Contract.Requires(expr != null); - throw new NotImplementedException(); - } - - public bool DoNotResolveOverloading - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - #endregion - } - - public class UnaryOperator : IAppliable { - private IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - public enum Opcode { - Neg, - Not - }; - private Opcode op; - public Opcode Op { - get { - return op; - } - } - public UnaryOperator(IToken tok, Opcode op) { - Contract.Requires(tok != null); - this.tok = tok; - this.op = op; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is UnaryOperator)) - return false; - - UnaryOperator other = (UnaryOperator)obj; - return object.Equals(this.op, other.op); - } - [Pure] - public override int GetHashCode() { - return (int)this.op; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - switch (this.op) { - case Opcode.Neg: - return "-"; - case Opcode.Not: - return "!"; - } - System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); - throw new Exception(); - } - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.SetToken(ref this.tok); - Contract.Assert(args.Count == 1); - // determine if parens are needed - int opBindingStrength = 0x70; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - stream.Write(FunctionName); - cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); - if (parensNeeded) { - stream.Write(")"); - } - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - if (rc.TriggerMode && this.op == Opcode.Not) { - rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); - } - } - - public int ArgumentCount { - get { - return 1; - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(Contract.ValueAtReturn(out args) != null); - - Contract.Assume(args.Count == 1); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - Type arg0type = cce.NonNull(cce.NonNull(args[0]).Type); - switch (this.op) { - case Opcode.Neg: - if (arg0type.Unify(Type.Int)) { - return Type.Int; - } - if (arg0type.Unify(Type.Real)) { - return Type.Real; - } - goto BAD_TYPE; - case Opcode.Not: - if (arg0type.Unify(Type.Bool)) { - return Type.Bool; - } - goto BAD_TYPE; - } - System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - BAD_TYPE: - tc.Error(this.tok, "invalid argument type ({1}) to unary operator {0}", - this.FunctionName, arg0type); - return null; - } - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - switch (this.op) { - case Opcode.Neg: - return cce.NonNull(cce.NonNull(args[0]).Type); - case Opcode.Not: - return Type.Bool; - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // unexpected unary operator - } - } - - public object Evaluate(object argument) { - if (argument == null) { - return null; - } - switch (this.op) { - case Opcode.Neg: - if (argument is BigNum) { - return -((BigNum)argument); - } - if (argument is BigDec) { - return -((BigDec)argument); - } - break; - case Opcode.Not: - if (argument is bool) { - return !((bool)argument); - } - throw new System.InvalidOperationException("unary Not only applies to bool"); - } - return null; // unreachable - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class BinaryOperator : IAppliable, IOverloadedAppliable { - private IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - public bool DoNotResolveOverloading { get; set; } - - public enum Opcode { - Add, - Sub, - Mul, - Div, - Mod, - RealDiv, - Pow, - Eq, - Neq, - Gt, - Ge, - Lt, - Le, - And, - Or, - Imp, - Iff, - Subtype - }; - private Opcode op; - public Opcode Op { - get { - return op; - } - } - public BinaryOperator(IToken tok, Opcode op) { - Contract.Requires(tok != null); - this.tok = tok; - this.op = op; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BinaryOperator)) - return false; - - BinaryOperator other = (BinaryOperator)obj; - return object.Equals(this.op, other.op); - } - - [Pure] - public override int GetHashCode() { - return (int)this.op << 1; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - switch (this.op) { - case Opcode.Add: - return "+"; - case Opcode.Sub: - return "-"; - case Opcode.Mul: - return "*"; - case Opcode.Div: - return "div"; - case Opcode.Mod: - return "mod"; - case Opcode.RealDiv: - return "/"; - case Opcode.Pow: - return "**"; - case Opcode.Eq: - return "=="; - case Opcode.Neq: - return "!="; - case Opcode.Gt: - return ">"; - case Opcode.Ge: - return ">="; - case Opcode.Lt: - return "<"; - case Opcode.Le: - return "<="; - case Opcode.And: - return "&&"; - case Opcode.Or: - return "||"; - case Opcode.Imp: - return "==>"; - case Opcode.Iff: - return "<==>"; - case Opcode.Subtype: - return "<:"; - } - System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); - throw new Exception(); - } - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.SetToken(ref this.tok); - Contract.Assert(args.Count == 2); - // determine if parens are needed - int opBindingStrength; - bool fragileLeftContext = false; // false means "allow same binding power on left without parens" - bool fragileRightContext = false; // false means "allow same binding power on right without parens" - switch (this.op) { - case Opcode.Add: - opBindingStrength = 0x40; - break; - case Opcode.Sub: - opBindingStrength = 0x40; - fragileRightContext = true; - break; - case Opcode.Mul: - opBindingStrength = 0x50; - break; - case Opcode.Div: - opBindingStrength = 0x50; - fragileRightContext = true; - break; - case Opcode.Mod: - opBindingStrength = 0x50; - fragileRightContext = true; - break; - case Opcode.RealDiv: - opBindingStrength = 0x50; - fragileRightContext = true; - break; - case Opcode.Pow: - opBindingStrength = 0x60; - fragileRightContext = true; - break; - case Opcode.Eq: - case Opcode.Neq: - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - case Opcode.Subtype: - opBindingStrength = 0x30; - fragileLeftContext = fragileRightContext = true; - break; - case Opcode.And: - opBindingStrength = 0x20; - break; - case Opcode.Or: - opBindingStrength = 0x21; - break; - case Opcode.Imp: - opBindingStrength = 0x10; - fragileLeftContext = true; - break; - case Opcode.Iff: - opBindingStrength = 0x00; - break; - default: - System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); - opBindingStrength = -1; // to please compiler, which refuses to consider whether or not all enumeration cases have been considered! - break; - } - int opBS = opBindingStrength & 0xF0; - int ctxtBS = contextBindingStrength & 0xF0; - bool parensNeeded = opBS < ctxtBS || - (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext)); - - var pop = stream.push(FunctionName); - if (parensNeeded) { - stream.Write("("); - } - cce.NonNull(args[0]).Emit(stream, opBindingStrength, fragileLeftContext); - stream.sep(); - stream.Write(" {0} ", FunctionName); - cce.NonNull(args[1]).Emit(stream, opBindingStrength, fragileRightContext); - if (parensNeeded) { - stream.Write(")"); - } - stream.pop(pop); - } - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - if (rc.TriggerMode) { - switch (this.op) { - case Opcode.Add: - case Opcode.Sub: - case Opcode.Mul: - case Opcode.Div: - case Opcode.Mod: - case Opcode.RealDiv: - case Opcode.Pow: - case Opcode.Neq: // Neq is allowed, but not Eq - case Opcode.Subtype: - // These are fine - break; - - case Opcode.Eq: - rc.Error(subjectForErrorReporting, "equality is not allowed in triggers"); - break; - - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - rc.Error(subjectForErrorReporting, "arithmetic comparisons are not allowed in triggers"); - break; - - case Opcode.And: - case Opcode.Or: - case Opcode.Imp: - case Opcode.Iff: - rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); - break; - - default: - System.Diagnostics.Debug.Fail("unknown binary operator: " + this.op.ToString()); - break; - } - } - } - public int ArgumentCount { - get { - return 2; - } - } - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(args != null); - Contract.Assert(args.Count == 2); - // the default; the only binary operator with a type parameter is equality, but right - // we don't store this parameter because it does not appear necessary - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - Expr arg0 = cce.NonNull(args[0]); - Expr arg1 = cce.NonNull(args[1]); - Type arg0type = cce.NonNull(arg0.Type); - Type arg1type = cce.NonNull(arg1.Type); - switch (this.op) { - case Opcode.Add: - case Opcode.Sub: - case Opcode.Mul: - if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { - return Type.Int; - } - if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { - return Type.Real; - } - goto BAD_TYPE; - case Opcode.Div: - case Opcode.Mod: - if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { - return Type.Int; - } - goto BAD_TYPE; - case Opcode.RealDiv: - if ((arg0type.Unify(Type.Int) || arg0type.Unify(Type.Real)) && - (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real))) { - return Type.Real; - } - goto BAD_TYPE; - case Opcode.Pow: - if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { - return Type.Real; - } - goto BAD_TYPE; - case Opcode.Eq: - case Opcode.Neq: - // Comparison is allowed if the argument types are unifiable - // (i.e., if there is any chance that the values of the arguments are - // in the same domain) - if (arg0type.Equals(arg1type)) { - // quick path - return Type.Bool; - } - List/*!*/ unifiable = new List(); - unifiable.AddRange(arg0type.FreeVariables); - unifiable.AddRange(arg1type.FreeVariables); - - if (arg0type.Unify(arg1type, unifiable, new Dictionary())) - return Type.Bool; - goto BAD_TYPE; - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { - return Type.Bool; - } - if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { - return Type.Bool; - } - goto BAD_TYPE; - case Opcode.And: - case Opcode.Or: - case Opcode.Imp: - case Opcode.Iff: - if (arg0type.Unify(Type.Bool) && arg1type.Unify(Type.Bool)) { - return Type.Bool; - } - goto BAD_TYPE; - case Opcode.Subtype: - // Subtype is polymorphically typed and can compare things of - // arbitrary types (but both arguments must have the same type) - if (arg0type.Unify(arg1type)) { - return Type.Bool; - } - goto BAD_TYPE; - } - System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } - BAD_TYPE: - tc.Error(this.tok, "invalid argument types ({1} and {2}) to binary operator {0}", this.FunctionName, arg0type, arg1type); - return null; - } - - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - switch (this.op) { - case Opcode.Add: - case Opcode.Sub: - case Opcode.Mul: - return cce.NonNull(args[0]).ShallowType; - - case Opcode.Div: - case Opcode.Mod: - return Type.Int; - - case Opcode.RealDiv: - case Opcode.Pow: - return Type.Real; - - case Opcode.Eq: - case Opcode.Neq: - case Opcode.Gt: - case Opcode.Ge: - case Opcode.Lt: - case Opcode.Le: - case Opcode.And: - case Opcode.Or: - case Opcode.Imp: - case Opcode.Iff: - case Opcode.Subtype: - return Type.Bool; - - default: { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // unexpected binary operator - } - } - - public void ResolveOverloading(NAryExpr expr) { - //Contract.Requires(expr != null); - - // immutable Expr must not be modified - if (DoNotResolveOverloading || expr.Immutable) - { - return; - } - - Expr arg0 = cce.NonNull(expr.Args[0]); - Expr arg1 = cce.NonNull(expr.Args[1]); - switch (op) { - case Opcode.Eq: - if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { - expr.Fun = new BinaryOperator(tok, Opcode.Iff); - } - break; - case Opcode.Neq: - if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { - expr.Fun = new BinaryOperator(tok, Opcode.Iff); - var arg1New = new NAryExpr(expr.tok, new UnaryOperator(tok, UnaryOperator.Opcode.Not), new List { arg1 }); - - // ugly ... there should be some more general approach, - // e.g., to typecheck the whole expression again - arg1New.Type = Type.Bool; - arg1New.TypeParameters = SimpleTypeParamInstantiation.EMPTY; - - expr.Args[1] = arg1New; - } - break; - } - } - - public object Evaluate(object e1, object e2) { - if (e1 == null || e2 == null) { - return null; - } - - switch (this.op) { - case Opcode.Add: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) + ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) + ((BigDec)e2); - } - break; - case Opcode.Sub: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) - ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) - ((BigDec)e2); - } - break; - case Opcode.Mul: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) * ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) * ((BigDec)e2); - } - break; - case Opcode.Div: - if (e1 is BigNum && e2 is BigNum) { - return /* TODO: right semantics? */ ((BigNum)e1) / ((BigNum)e2); - } - break; - case Opcode.Mod: - if (e1 is BigNum && e2 is BigNum) { - return /* TODO: right semantics? */ ((BigNum)e1) % ((BigNum)e2); - } - break; - case Opcode.RealDiv: - // TODO: add partial evaluation fro real division - break; - case Opcode.Pow: - // TODO: add partial evaluation fro real exponentiation - break; - case Opcode.Lt: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) < ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) < ((BigDec)e2); - } - break; - case Opcode.Le: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) <= ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) <= ((BigDec)e2); - } - break; - case Opcode.Gt: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) > ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) > ((BigDec)e2); - } - break; - case Opcode.Ge: - if (e1 is BigNum && e2 is BigNum) { - return ((BigNum)e1) >= ((BigNum)e2); - } - if (e1 is BigDec && e2 is BigDec) { - return ((BigDec)e1) >= ((BigDec)e2); - } - break; - - case Opcode.And: - if (e1 is bool && e2 is bool) { - return (bool)e1 && (bool)e2; - } - break; - case Opcode.Or: - if (e1 is bool && e2 is bool) { - return (bool)e1 || (bool)e2; - } - break; - case Opcode.Imp: - if (e1 is bool && e2 is bool) { - return !(bool)e1 || (bool)e2; - } - break; - case Opcode.Iff: - if (e1 is bool && e2 is bool) { - return e1 == e2; - } - break; - - case Opcode.Eq: - return Equals(e1, e2); - case Opcode.Neq: - return !Equals(e1, e2); - - case Opcode.Subtype: - throw new System.NotImplementedException(); - } - throw new System.InvalidOperationException("bad types to binary operator " + this.op); - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - - } - - public class FunctionCall : IAppliable { - private IdentifierExpr/*!*/ name; - public Function Func; - public FunctionCall(IdentifierExpr name) { - Contract.Requires(name != null); - this.name = name; - } - public FunctionCall(Function f) { - Contract.Requires(f != null); - this.Func = f; - this.name = new IdentifierExpr(Token.NoToken, f.Name); - - // We need set the type of this IdentifierExpr so ShallowType() works - Debug.Assert(f.OutParams.Count > 0); - this.name.Type = f.OutParams[0].TypedIdent.Type; - } - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - return this.name.Name; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(name != null); - } - - public FunctionCall createUnresolvedCopy() - { - return new FunctionCall(new IdentifierExpr(name.tok, name.Name, name.Type)); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return name.Name; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - FunctionCall fc = other as FunctionCall; - return fc != null && this.Func == fc.Func; - } - [Pure] - public override int GetHashCode() { - Contract.Assume(this.Func != null); - return Func.GetHashCode(); - } - - virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - - if (stream.UseForComputingChecksums && Func.OriginalLambdaExprAsString != null) - { - stream.Write(Func.OriginalLambdaExprAsString); - } - else - { - this.name.Emit(stream, 0xF0, false); - } - if (stream.UseForComputingChecksums) - { - var c = Func.DependencyChecksum; - if (c != null) - { - stream.Write(string.Format("[dependency_checksum:{0}]", c)); - } - } - stream.Write("("); - args.Emit(stream); - stream.Write(")"); - } - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - if (Func != null) { - // already resolved - return; - } - Func = rc.LookUpProcedure(name.Name) as Function; - if (Func == null) { - rc.Error(this.name, "use of undeclared function: {0}", name.Name); - } - else if (name.Type == null) { - // We need set the type of this IdentifierExpr so ShallowType() works - Debug.Assert(name.Type == null); - Debug.Assert(Func.OutParams.Count > 0); - name.Type = Func.OutParams[0].TypedIdent.Type; - } - } - public virtual int ArgumentCount { - get { - Contract.Assume(Func != null); // ArgumentCount requires object to be properly resolved. - return Func.InParams.Count; - } - } - public virtual Type Typecheck(IList actuals, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(actuals != null); - Contract.Ensures(Contract.ValueAtReturn(out actuals) != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Assume(this.Func != null); - Contract.Assume(actuals.Count == Func.InParams.Count); - Contract.Assume(Func.OutParams.Count == 1); - - List/*!*/ resultingTypeArgs; - List actualResultType = - Type.CheckArgumentTypes(Func.TypeParameters, - out resultingTypeArgs, - new List(Func.InParams.Select(Item => Item.TypedIdent.Type).ToArray()), - actuals, - new List(Func.OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), - null, - // we need some token to report a possibly wrong number of - // arguments - actuals.Count > 0 ? cce.NonNull(actuals[0]).tok : Token.NoToken, - "application of " + name.Name, - tc); - - if (actualResultType == null) { - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } else { - Contract.Assert(actualResultType.Count == 1); - tpInstantiation = - SimpleTypeParamInstantiation.From(Func.TypeParameters, resultingTypeArgs); - return actualResultType[0]; - } - } - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - Contract.Assume(name.Type != null); - return name.Type; - } - - public virtual T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class TypeCoercion : IAppliable { - private IToken/*!*/ tok; - public Type/*!*/ Type; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - public TypeCoercion(IToken tok, Type type) { - Contract.Requires(type != null); - Contract.Requires(tok != null); - this.tok = tok; - this.Type = type; - } - - public override bool Equals(object obj) { - TypeCoercion other = obj as TypeCoercion; - if (other == null) { - return false; - } else { - return object.Equals(Type, other.Type); - } - } - - - - public - string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return ":"; - } - } - - public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - //Contract.Requires(args != null); - //Contract.Requires(stream != null); - stream.SetToken(ref this.tok); - Contract.Assert(args.Count == 1); - // determine if parens are needed - int opBindingStrength = 0x80; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) - stream.Write("("); - - cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); - stream.Write("{0} ", FunctionName); - Type.Emit(stream, 0); - - if (parensNeeded) - stream.Write(")"); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - this.Type = this.Type.ResolveType(rc); - } - - public int ArgumentCount { - get { - return 1; - } - } - - public Type Typecheck(IList/*!*/ args, - out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc) { - //Contract.Requires(args != null); - //Contract.Requires(tc != null); - Contract.Ensures(args != null); - - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - Contract.Assume(args.Count == 1); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - - if (!this.Type.Unify(cce.NonNull(cce.NonNull(args[0]).Type))) - tc.Error(this.tok, "{0} cannot be coerced to {1}", - cce.NonNull(args[0]).Type, this.Type); - return this.Type; - } - - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return this.Type; - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - - } - - public class ArithmeticCoercion : IAppliable { - public enum CoercionType { - ToInt, - ToReal - } - - private IToken/*!*/ tok; - public readonly CoercionType Coercion; - private readonly string name; - private readonly Type type; - private readonly Type argType; - private readonly int hashCode; - - public ArithmeticCoercion(IToken tok, CoercionType coercion) { - this.tok = tok; - this.Coercion = coercion; - - switch (coercion) { - case CoercionType.ToInt: - this.name = "int"; - this.type = Type.Int; - this.argType = Type.Real; - this.hashCode = 1; - break; - case CoercionType.ToReal: - this.name = "real"; - this.type = Type.Real; - this.argType = Type.Int; - this.hashCode = 2; - break; - default: - Contract.Assert(false); - break; - } - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return this.name; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object other) { - ArithmeticCoercion ac = other as ArithmeticCoercion; - return ac != null && this.Coercion == ac.Coercion; - } - - [Pure] - public override int GetHashCode() { - return this.hashCode; - } - - public string/*!*/ FunctionName { - get { - return this.name; - } - } - - public int ArgumentCount { - get { - return 1; - } - } - - virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.Write(this.name); - stream.Write("("); - args.Emit(stream); - stream.Write(")"); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - } - - public virtual Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - Contract.Assert(args.Count == 1); - - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - - if (!cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType)) { - tc.Error(this.tok, "argument type {0} does not match expected type {1}", cce.NonNull(args[0]).Type, this.argType); - } - - return this.type; - } - - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return this.type; - } - - public virtual T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class NAryExpr : Expr { - [Additive] - [Peer] - private IAppliable _Fun; - public IAppliable/*!*/ Fun { - get { - return _Fun; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Function used by Immutable NAryExpr"); - - _Fun = value; - } - } - private List _Args; - public IList Args { - get { - if (Immutable) - return _Args.AsReadOnly(); - else - return _Args; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change Args of Immutable NAryExpr"); - - _Args = value as List; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Fun != null); - Contract.Invariant(Args != null); - } - - - // The instantiation of type parameters that is determined during type checking. - // Which type parameters are available depends on the IAppliable - public TypeParamInstantiation TypeParameters = null; - - [Captured] - public NAryExpr(IToken/*!*/ tok, IAppliable/*!*/ fun, IList/*!*/ args, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(fun != null); - Contract.Requires(args != null); - _Fun = fun; - Contract.Assert(Contract.ForAll(0, args.Count, index => args[index] != null)); - if (immutable) { - // We need to make a new list because the client might be holding - // references to the list that they gave us which could be used to - // circumvent the immutability enforcement - _Args = new List(args); - CachedHashCode = ComputeHashCode(); - } else { - if (args is List) { - // Preserve NAryExpr's old behaviour, we take ownership of the List. - // We can only do this if the type matches - _Args = args as List; - } - else { - // Otherwise we must make a copy - _Args = new List (args); - } - } - } - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is NAryExpr)) - return false; - - NAryExpr other = (NAryExpr)obj; - return object.Equals(this.Fun, other.Fun) && this.Args.SequenceEqual(other.Args); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return this.CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.Fun.GetHashCode(); - // DO NOT USE Args.GetHashCode() because that uses Object.GetHashCode() which uses references - // We want structural equality - foreach (var arg in Args) { - h = (97*h) + arg.GetHashCode(); - } - return h; - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - Fun.Emit(Args, stream, contextBindingStrength, fragileContext); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Fun.Resolve(rc, this); - foreach (Expr/*!*/ e in Args) { - Contract.Assert(e != null); - e.Resolve(rc); - } - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - foreach (Expr/*!*/ e in Args) { - Contract.Assert(e != null); - e.ComputeFreeVariables(freeVars); - } - // also add the free type variables - if (TypeParameters != null) { - foreach (TypeVariable/*!*/ var in TypeParameters.FormalTypeParams) { - Contract.Assert(var != null); - foreach (TypeVariable/*!*/ w in TypeParameters[var].FreeVariables) { - Contract.Assert(w != null); - freeVars.Add(w); - } - } - } - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - int prevErrorCount = tc.ErrorCount; - foreach (Expr/*!*/ e in Args) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - if (Fun.ArgumentCount != Args.Count) { - tc.Error(this, "wrong number of arguments to function: {0} ({1} instead of {2})", - Fun.FunctionName, Args.Count, Fun.ArgumentCount); - } else if (tc.ErrorCount == prevErrorCount && - // if the type parameters are set, this node has already been - // typechecked and does not need to be checked again - TypeParameters == null) { - TypeParamInstantiation tpInsts; - Type = Fun.Typecheck(Args, out tpInsts, tc); // Make sure we pass Args so if this Expr is immutable it is protected - TypeParameters = tpInsts; - } - IOverloadedAppliable oa = Fun as IOverloadedAppliable; - if (oa != null) { - oa.ResolveOverloading(this); - } - if (Type == null) { - // set Type to some non-null value - Type = new TypeProxy(this.tok, "type_checking_error"); - } - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Fun.ShallowType(Args); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitNAryExpr(this); - } - } - - public class MapSelect : IAppliable { - - public readonly int Arity; - private readonly IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - - public MapSelect(IToken tok, int arity) { - Contract.Requires(tok != null); - this.tok = tok; - this.Arity = arity; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return "MapSelect"; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (!(obj is MapSelect)) - return false; - - MapSelect other = (MapSelect)obj; - return this.Arity == other.Arity; - } - - [Pure] - public override int GetHashCode() { - return Arity.GetHashCode() * 2823; - } - - public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - //Contract.Requires(args != null); - //Contract.Requires(stream != null); - Contract.Assume(args.Count == Arity + 1); - Emit(args, stream, contextBindingStrength, fragileContext, false); - } - - public static void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext, - bool withRhs) { - Contract.Requires(args != null); - Contract.Requires(stream != null); - const int opBindingStrength = 0x90; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); - stream.Write("["); - - string sep = ""; - int lastIndex = withRhs ? args.Count - 1 : args.Count; - for (int i = 1; i < lastIndex; ++i) { - stream.Write(sep); - sep = ", "; - cce.NonNull(args[i]).Emit(stream); - } - - if (withRhs) { - stream.Write(" := "); - cce.NonNull(args.Last()).Emit(stream); - } - - stream.Write("]"); - if (parensNeeded) { - stream.Write(")"); - } - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - // PR: nothing? - } - - public int ArgumentCount { - get { - return Arity + 1; - } - } - - // it is assumed that each of the arguments has already been typechecked - public static Type Typecheck(Type/*!*/ mapType, - // we just pass an Absy, because in - // the AssignCmd maps can also be - // represented by non-expressions - Absy/*!*/ map, - List/*!*/ indexes, - // the type parameters, in this context, are the parameters of the - // potentially polymorphic map type. Because it might happen that - // the whole map type is unknown and represented using a MapTypeProxy, - // the instantiations given in the following out-parameter are subject - // to change if further unifications are done. - out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName) { - Contract.Requires(mapType != null); - Contract.Requires(map != null); - Contract.Requires(indexes != null); - Contract.Requires(tc != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - mapType = mapType.Expanded; - if (mapType.IsMap && mapType.MapArity != indexes.Count) { - tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1} instead of {2}", - opName, indexes.Count, mapType.MapArity); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } else if (!mapType.Unify(new MapTypeProxy(map.tok, "select", indexes.Count))) { - tc.Error(map.tok, "{0} applied to a non-map: {1}", opName, map); - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } - mapType = TypeProxy.FollowProxy(mapType); - - if (mapType is MapType) { - MapType mt = (MapType)mapType; - return mt.CheckArgumentTypes(indexes, out tpInstantiation, - typeCheckingSubject, opName, tc); - } else { - MapTypeProxy mt = (MapTypeProxy)mapType; - return mt.CheckArgumentTypes(indexes, out tpInstantiation, - typeCheckingSubject, opName, tc); - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Assume(args.Count == Arity + 1); - - // FIXME: Wny are we passing a copy? - List actualArgs = new List(); - for (int i = 1; i < args.Count; ++i) - actualArgs.Add(args[i]); - - return Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), - actualArgs, out tpInstantiation, tc, this.tok, "map select"); - } - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - Expr a0 = cce.NonNull(args[0]); - Type a0Type = a0.ShallowType; - if (a0Type == null || !a0Type.IsMap) { - // we are unable to determine the type of the select, so just return an arbitrary type - return Type.Int; - } - MapType mapType = a0Type.AsMap; - List actualArgTypes = new List(); - for (int i = 1; i < args.Count; ++i) { - actualArgTypes.Add(cce.NonNull(args[i]).ShallowType); - } - return Type.InferValueType(mapType.TypeParameters, mapType.Arguments, mapType.Result, actualArgTypes); - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - public class MapStore : IAppliable { - - public readonly int Arity; - public readonly IToken/*!*/ tok; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(tok != null); - } - - - public MapStore(IToken tok, int arity) { - Contract.Requires(tok != null); - this.tok = tok; - this.Arity = arity; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return "MapStore"; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (!(obj is MapStore)) - return false; - - MapStore other = (MapStore)obj; - return this.Arity == other.Arity; - } - - [Pure] - public override int GetHashCode() { - return Arity.GetHashCode() * 28231; - } - - public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - //Contract.Requires(args != null); - //Contract.Requires(stream != null); - Contract.Assert(args.Count == Arity + 2); - MapSelect.Emit(args, stream, contextBindingStrength, fragileContext, true); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - // PR: nothing? - } - - public int ArgumentCount { - get { - return Arity + 2; - } - } - - // it is assumed that each of the arguments has already been typechecked - public static Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName) { - Contract.Requires(args != null); - Contract.Requires(tc != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - // part of the type checking works exactly as for MapSelect - List selectArgs = new List(); - for (int i = 1; i < args.Count - 1; ++i) - selectArgs.Add(args[i]); - Type resultType = - MapSelect.Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), - selectArgs, out tpInstantiation, tc, typeCheckingSubject, opName); - - // check the the rhs has the right type - if (resultType == null) { - // error messages have already been created by MapSelect.Typecheck - return null; - } - Type rhsType = cce.NonNull(cce.NonNull(args.Last()).Type); - if (!resultType.Unify(rhsType)) { - tc.Error(cce.NonNull(args.Last()).tok, - "right-hand side in {0} with wrong type: {1} (expected: {2})", - opName, rhsType, resultType); - return null; - } - - return cce.NonNull(args[0]).Type; - } - - public Type Typecheck(IList/*!*/ args, - out TypeParamInstantiation/*!*/ tpInstantiation, - TypecheckingContext/*!*/ tc) { - //Contract.Requires(args != null); - //Contract.Requires(tc != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Ensures(Contract.ValueAtReturn(out args) != null); - Contract.Assert(args.Count == Arity + 2); - return Typecheck(args, out tpInstantiation, tc, this.tok, "map store"); - } - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(args[0]).ShallowType; - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - - public class IfThenElse : IAppliable { - - private IToken/*!*/ _tok; - - public IToken/*!*/ tok - { - get - { - Contract.Ensures(Contract.Result() != null); - return this._tok; - } - set - { - Contract.Requires(value != null); - this._tok = value; - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this._tok != null); - } - - public IfThenElse(IToken tok) { - Contract.Requires(tok != null); - this._tok = tok; - } - - public string/*!*/ FunctionName { - get { - Contract.Ensures(Contract.Result() != null); - - return "if-then-else"; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (!(obj is IfThenElse)) - return false; - return true; - } - - [Pure] - public override int GetHashCode() { - return 1; - } - - public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //Contract.Requires(args != null); - stream.SetToken(this); - Contract.Assert(args.Count == 3); - stream.push(); - stream.Write("(if "); - cce.NonNull(args[0]).Emit(stream, 0x00, false); - stream.sep(); - stream.Write(" then "); - cce.NonNull(args[1]).Emit(stream, 0x00, false); - stream.sep(); - stream.Write(" else "); - cce.NonNull(args[2]).Emit(stream, 0x00, false); - stream.Write(")"); - stream.pop(); - } - - public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { - //Contract.Requires(subjectForErrorReporting != null); - //Contract.Requires(rc != null); - // PR: nothing? - } - - public int ArgumentCount { - get { - return 3; - } - } - - public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { - //Contract.Requires(tc != null); - //Contract.Requires(args != null); - Contract.Ensures(args != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - Contract.Assert(args.Count == 3); - // the default; the only binary operator with a type parameter is equality, but right - // we don't store this parameter because it does not appear necessary - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - Expr arg0 = cce.NonNull(args[0]); - Expr arg1 = cce.NonNull(args[1]); - Expr arg2 = cce.NonNull(args[2]); - - if (!cce.NonNull(arg0.Type).Unify(Type.Bool)) { - tc.Error(this.tok, "the first argument to if-then-else should be bool, not {0}", arg0.Type); - } else if (!cce.NonNull(arg1.Type).Unify(cce.NonNull(arg2.Type))) { - tc.Error(this.tok, "branches of if-then-else have incompatible types {0} and {1}", arg1.Type, arg2.Type); - } else { - return arg1.Type; - } - - return null; - } - - /// - /// Returns the result type of the IAppliable, supposing the argument are of the correct types. - /// - public Type ShallowType(IList args) { - //Contract.Requires(args != null); - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(args[1]).ShallowType; - } - - public T Dispatch(IAppliableVisitor visitor) { - //Contract.Requires(visitor != null); - return visitor.Visit(this); - } - } - - - - public class CodeExpr : Expr { - public List/*!*/ LocVars; - [Rep] - public List/*!*/ Blocks; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(LocVars != null); - Contract.Invariant(cce.NonNullElements(Blocks)); - } - - public CodeExpr(List/*!*/ localVariables, List/*!*/ blocks, bool immutable=false) - : base(Token.NoToken, immutable) { - Contract.Requires(localVariables != null); - Contract.Requires(cce.NonNullElements(blocks)); - Contract.Requires(0 < blocks.Count); - LocVars = localVariables; - Blocks = blocks; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - // FIXME: This seems wrong we don't want reference equality, we want structural equality - [Pure] - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - [Pure] - public override int GetHashCode() - { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - return base.GetHashCode(); - } - - - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - // Treat a BlockEexpr as if it has no free variables at all - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - //level++; - int level = 0; - stream.WriteLine(level, "|{"); - - if (this.LocVars.Count > 0) { - stream.Write(level + 1, "var "); - this.LocVars.Emit(stream, true); - stream.WriteLine(";"); - } - - foreach (Block/*!*/ b in this.Blocks) { - Contract.Assert(b != null); - b.Emit(stream, level + 1); - } - - stream.WriteLine(); - stream.WriteLine(level, "}|"); - - stream.WriteLine(); - stream.WriteLine(); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - - rc.PushVarContext(); - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Register(rc); - v.Resolve(rc); - } - - rc.PushProcedureContext(); - foreach (Block/*!*/ b in Blocks) { - Contract.Assert(b != null); - b.Register(rc); - } - - foreach (Block/*!*/ b in Blocks) { - Contract.Assert(b != null); - b.Resolve(rc); - } - - rc.PopProcedureContext(); - rc.PopVarContext(); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (Variable/*!*/ v in LocVars) { - Contract.Assert(v != null); - v.Typecheck(tc); - } - foreach (Block/*!*/ b in Blocks) { - Contract.Assert(b != null); - b.Typecheck(tc); - } - this.Type = Type.Bool; - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Type.Bool; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitCodeExpr(this); - } - } - - public class BvExtractExpr : Expr { - private /*readonly--except in StandardVisitor*/ Expr/*!*/ _Bitvector; - public Expr Bitvector { - get { - return _Bitvector; - } - set { - if (Immutable) - throw new InvalidOperationException("Cannot change BitVector field of an immutable BvExtractExpr"); - - _Bitvector = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(_Bitvector != null); - } - - public readonly int Start, End; - - public BvExtractExpr(IToken/*!*/ tok, Expr/*!*/ bv, int end, int start, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(bv != null); - _Bitvector = bv; - Start = start; - End = end; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BvExtractExpr)) - return false; - - BvExtractExpr other = (BvExtractExpr)obj; - return object.Equals(this.Bitvector, other.Bitvector) && - this.Start.Equals(other.Start) && this.End.Equals(other.End); - } - - [Pure] - public override int GetHashCode() { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.Bitvector.GetHashCode(); - h ^= Start * 17 ^ End * 13; - return h; - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - int opBindingStrength = 0x90; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - Bitvector.Emit(stream, opBindingStrength, false); - stream.Write("[" + End + ":" + Start + "]"); - if (parensNeeded) { - stream.Write(")"); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - Bitvector.Resolve(rc); - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - Bitvector.ComputeFreeVariables(freeVars); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - Bitvector.Typecheck(tc); - Contract.Assert(Bitvector.Type != null); // follows from postcondition of Expr.Typecheck - - if (Start < 0) { - tc.Error(this, "start index in extract must not be negative"); - } else if (End < 0) { - tc.Error(this, "end index in extract must not be negative"); - } else if (End < Start) { - tc.Error(this, "start index in extract must be no bigger than the end index"); - } else { - Type typeConstraint = new BvTypeProxy(this.tok, "extract", End - Start); - if (typeConstraint.Unify(Bitvector.Type)) { - Type = Type.GetBvType(End - Start); - } else { - tc.Error(this, "extract operand must be a bitvector of at least {0} bits (got {1})", End - Start, Bitvector.Type); - } - } - if (Type == null) { - Type = new TypeProxy(this.tok, "type_checking_error"); - } - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Type.GetBvType(End - Start); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvExtractExpr(this); - } - } - - public class BvConcatExpr : Expr { - private /*readonly--except in StandardVisitor*/ Expr/*!*/ _E0, _E1; - public Expr E0 { - get { - return _E0; - } - set { - if (Immutable) - throw new InvalidOperationException("Can't change E0 reference on immutable Expr"); - - _E0 = value; - } - } - public Expr E1 { - get { - return _E1; - } - set { - if (Immutable) - throw new InvalidOperationException("Can't change E1 reference on immutable Expr"); - - _E1 = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(E0 != null); - Contract.Invariant(E1 != null); - } - - - public BvConcatExpr(IToken/*!*/ tok, Expr/*!*/ e0, Expr/*!*/ e1, bool immutable=false) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(e0 != null); - Contract.Requires(e1 != null); - _E0 = e0; - _E1 = e1; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is BvConcatExpr)) - return false; - - BvConcatExpr other = (BvConcatExpr)obj; - return object.Equals(this.E0, other.E0) && object.Equals(this.E1, other.E1); - } - - [Pure] - public override int GetHashCode() - { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - int h = this.E0.GetHashCode() ^ this.E1.GetHashCode() * 17; - return h; - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.SetToken(this); - int opBindingStrength = 0x32; - bool parensNeeded = opBindingStrength < contextBindingStrength || - (fragileContext && opBindingStrength == contextBindingStrength); - - if (parensNeeded) { - stream.Write("("); - } - E0.Emit(stream, opBindingStrength, false); - stream.Write(" ++ "); - // while this operator is associative, our incomplete axioms in int translation don't - // make much use of it, so better stick to the actual tree shape - E1.Emit(stream, opBindingStrength, true); - if (parensNeeded) { - stream.Write(")"); - } - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - E0.Resolve(rc); - E1.Resolve(rc); - } - public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { - //Contract.Requires(freeVars != null); - E0.ComputeFreeVariables(freeVars); - E1.ComputeFreeVariables(freeVars); - } - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - E0.Typecheck(tc); - Contract.Assert(E0.Type != null); // follows from postcondition of Expr.Typecheck - E1.Typecheck(tc); - Contract.Assert(E1.Type != null); // follows from postcondition of Expr.Typecheck - - if (E0.Type.Unify(new BvTypeProxy(this.tok, "concat0", 0)) && E1.Type.Unify(new BvTypeProxy(this.tok, "concat1", 0))) { - Type = new BvTypeProxy(this.tok, "concat", E0.Type, E1.Type); - } else { - tc.Error(this, "++ operands need to be bitvectors (got {0}, {1})", E0.Type, E1.Type); - } - if (Type == null) { - Type = new TypeProxy(this.tok, "type_checking_error"); - } - } - - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - Type t0 = E0.ShallowType; - Type t1 = E1.ShallowType; - int len0 = t0.IsBv ? t0.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; - int len1 = t1.IsBv ? t1.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; - return Type.GetBvType(len0 + len1); - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvConcatExpr(this); - } - } -} - +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + using System.Linq; + using Microsoft.Basetypes; + + using Set = GSet; // not that the set used is not a set of Variable only, as it also contains TypeVariables + + + //--------------------------------------------------------------------- + // Expressions + // + // For expressions, we override the Equals and GetHashCode method to + // implement structural equality. Note this is not logical equivalence + // and is not modulo alpha-renaming. + //--------------------------------------------------------------------- + + + [ContractClass(typeof(ExprContracts))] + public abstract class Expr : Absy { + public Expr(IToken/*!*/ tok, bool immutable) + : base(tok) { + Contract.Requires(tok != null); + this.Immutable = immutable; + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + Emit(stream, 0, false); + } + + /// + /// If true the client is making a promise that this Expr will be + /// treated immutably (i.e. once constructed it is never changed). + /// This is currently not enforced but it should be! + /// + /// This allows the Expr's hash code to be cached making calls to + /// GetHashCode() very cheap. + /// + /// true if immutable; otherwise, false. + public bool Immutable { + get; + private set; + } + + /// + /// Computes the hash code of this Expr skipping any cache. + /// + /// Sub classes should place their implementation of computing their hashcode + /// here (making sure to call GetHashCode() not ComputeHashCode() on Expr for performance reasons) + /// and have GetHashCode() use a cached result from ComputeHashCode() if the + /// Expr was constructed to be immutable. + /// + /// The hash code. + public abstract int ComputeHashCode(); + protected int CachedHashCode = 0; + + public abstract void Emit(TokenTextWriter/*!*/ wr, int contextBindingStrength, bool fragileContext); + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/ false, /*pretty=*/ false)) { + this.Emit(stream, 0, false); + } + return buffer.ToString(); + } + + /// + /// Add to "freeVars" the free variables in the expression. + /// + public abstract void ComputeFreeVariables(Set /*Variable*//*!*/ freeVars); + + /// + /// Filled in by the Typecheck method. A value of "null" means a succeeding + /// call to Typecheck has not taken place (that is, either Typecheck hasn't + /// been called or Typecheck encountered an error in the expression to be + /// typechecked). + /// + private Type _Type = null; + public Type Type { + get { + return _Type; + } + set { + if (_Type == null) { + // Expr has never been type checked so always allow this + _Type = value; + } else { + if (Immutable && !_Type.Equals(value)) + throw new InvalidOperationException("Cannot change the Type of an Immutable Expr"); + + // Once the Type has been set (i.e. no longer null) we never change the reference + // if this Expr is immutable, even if the Type is equivalent (i.e. _Type.Equals(newType)) + if (!Immutable) + _Type = value; + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Contract.Ensures(Type != null); + // This body is added only because C# insists on it. It should really be left out, as if TypeCheck still were abstract. + // The reason for mentioning the method here at all is to give TypeCheck a postcondition for all expressions. + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + + /// + /// Returns the type of the expression, supposing that all its subexpressions are well typed. + /// + public abstract Type/*!*/ ShallowType { + get; + } + + // Handy syntactic sugar follows: + + public static NAryExpr Unary(IToken x, UnaryOperator.Opcode op, Expr e1) { + Contract.Requires(e1 != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + return new NAryExpr(x, new UnaryOperator(x, op), new List { e1 }); + } + + public static NAryExpr Binary(IToken x, BinaryOperator.Opcode op, Expr e0, Expr e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + return new NAryExpr(x, new BinaryOperator(x, op), new List { e0, e1 }); + } + + public static NAryExpr Binary(BinaryOperator.Opcode op, Expr e0, Expr e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(Token.NoToken, op, e0, e1); + } + + public static NAryExpr Eq(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Eq, e1, e2); + } + public static NAryExpr Neq(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Neq, e1, e2); + } + public static NAryExpr Le(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Le, e1, e2); + } + public static NAryExpr Ge(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Ge, e1, e2); + } + public static NAryExpr Lt(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Lt, e1, e2); + } + public static NAryExpr Gt(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Gt, e1, e2); + } + public static Expr And(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + if (e1 == true_) { + return e2; + } else if (e2 == true_) { + return e1; + } else if (e1 == false_ || e2 == false_) { + return false_; + } else { + var res = Binary(BinaryOperator.Opcode.And, e1, e2); + res.Type = Microsoft.Boogie.Type.Bool; + res.TypeParameters = SimpleTypeParamInstantiation.EMPTY; + return res; + } + } + public static Expr Or(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + if (e1 == false_) { + return e2; + } else if (e2 == false_) { + return e1; + } else if (e1 == true_ || e2 == true_) { + return true_; + } else { + return Binary(BinaryOperator.Opcode.Or, e1, e2); + } + } + public static Expr Not(Expr e1) { + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + NAryExpr nary = e1 as NAryExpr; + + if (e1 == true_) { + return false_; + } else if (e1 == false_) { + return true_; + } else if (nary != null) { + if (nary.Fun is UnaryOperator) { + UnaryOperator op = (UnaryOperator)nary.Fun; + if (op.Op == UnaryOperator.Opcode.Not) { + return cce.NonNull(nary.Args[0]); + } + } else if (nary.Fun is BinaryOperator) { + BinaryOperator op = (BinaryOperator)nary.Fun; + Expr arg0 = cce.NonNull(nary.Args[0]); + Expr arg1 = cce.NonNull(nary.Args[1]); + if (op.Op == BinaryOperator.Opcode.Eq) { + return Neq(arg0, arg1); + } else if (op.Op == BinaryOperator.Opcode.Neq) { + return Eq(arg0, arg1); + } else if (op.Op == BinaryOperator.Opcode.Lt) { + return Le(arg1, arg0); + } else if (op.Op == BinaryOperator.Opcode.Le) { + return Lt(arg1, arg0); + } else if (op.Op == BinaryOperator.Opcode.Ge) { + return Gt(arg1, arg0); + } else if (op.Op == BinaryOperator.Opcode.Gt) { + return Ge(arg1, arg0); + } + } + } + + return Unary(Token.NoToken, UnaryOperator.Opcode.Not, e1); + } + + public static Expr Neg(Expr e1) { + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Unary(Token.NoToken, UnaryOperator.Opcode.Neg, e1); + } + + public static NAryExpr Imp(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Imp, e1, e2); + } + public static NAryExpr Iff(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Iff, e1, e2); + } + public static NAryExpr Add(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Add, e1, e2); + } + public static NAryExpr Sub(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Sub, e1, e2); + } + public static NAryExpr Mul(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Mul, e1, e2); + } + public static NAryExpr Div(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Div, e1, e2); + } + public static NAryExpr Mod(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Mod, e1, e2); + } + public static NAryExpr RealDiv(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.RealDiv, e1, e2); + } + public static NAryExpr Pow(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Pow, e1, e2); + } + public static NAryExpr Subtype(Expr e1, Expr e2) { + Contract.Requires(e2 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result() != null); + return Binary(BinaryOperator.Opcode.Subtype, e1, e2); + } + + public static IdentifierExpr Ident(string name, Type type) { + Contract.Requires(type != null); + Contract.Requires(name != null); + Contract.Ensures(Contract.Result() != null); + return new IdentifierExpr(Token.NoToken, name, type); + } + + public static IdentifierExpr Ident(Variable decl) { + Contract.Requires(decl != null); + Contract.Ensures(Contract.Result() != null); + IdentifierExpr result = new IdentifierExpr(Token.NoToken, decl); + return result; + } + + public static LiteralExpr Literal(bool value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + public static LiteralExpr Literal(int value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, BigNum.FromInt(value)); + } + public static LiteralExpr Literal(BigNum value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + public static LiteralExpr Literal(BigDec value) { + Contract.Ensures(Contract.Result() != null); + return new LiteralExpr(Token.NoToken, value); + } + + private static LiteralExpr/*!*/ true_ = Literal(true); + public static LiteralExpr/*!*/ True { + get { + Contract.Ensures(Contract.Result() != null); + return true_; + } + } + + private static LiteralExpr/*!*/ false_ = Literal(false); + public static LiteralExpr/*!*/ False { + get { + Contract.Ensures(Contract.Result() != null); + return false_; + } + } + + + public static NAryExpr Select(Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Ensures(Contract.Result() != null); + return SelectTok(Token.NoToken, map, args); + } + + public static NAryExpr Select(Expr map, List/*!*/ args) { + Contract.Requires(map != null); + Contract.Requires(cce.NonNullElements(args)); + Contract.Ensures(Contract.Result() != null); + return Select(map, args.ToArray()); + } + + // use a different name for this variant of the method + // (-> some bug prevents overloading in this case) + public static NAryExpr SelectTok(IToken x, Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ allArgs = new List(); + allArgs.Add(map); + foreach (Expr/*!*/ a in args) { + Contract.Assert(a != null); + allArgs.Add(a); + } + return new NAryExpr(x, new MapSelect(Token.NoToken, args.Length), allArgs); + } + + public static NAryExpr Store(Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Ensures(Contract.Result() != null); + return StoreTok(Token.NoToken, map, args); + } + + public static NAryExpr Store(Expr map, List/*!*/ indexes, Expr rhs) { + Contract.Requires(rhs != null); + Contract.Requires(map != null); + Contract.Requires(cce.NonNullElements(indexes)); + Contract.Ensures(Contract.Result() != null); + Expr[]/*!*/ allArgs = new Expr[indexes.Count + 1]; + for (int i = 0; i < indexes.Count; ++i) + allArgs[i] = indexes[i]; + allArgs[indexes.Count] = rhs; + return Store(map, allArgs); + } + + // use a different name for this variant of the method + // (-> some bug prevents overloading in this case) + public static NAryExpr/*!*/ StoreTok(IToken x, Expr map, params Expr[] args) { + Contract.Requires(args != null); + Contract.Requires(map != null); + Contract.Requires(x != null); + Contract.Requires(args.Length > 0); // zero or more indices, plus the value + Contract.Ensures(Contract.Result() != null); + + List/*!*/ allArgs = new List(); + allArgs.Add(map); + foreach (Expr/*!*/ a in args) { + Contract.Assert(a != null); + allArgs.Add(a); + } + return new NAryExpr(x, new MapStore(Token.NoToken, args.Length - 1), allArgs); + } + + public static NAryExpr CoerceType(IToken x, Expr subexpr, Type type) { + Contract.Requires(type != null); + Contract.Requires(subexpr != null); + Contract.Requires(x != null); + Contract.Ensures(Contract.Result() != null); + List/*!*/ args = new List(); + args.Add(subexpr); + return new NAryExpr(x, new TypeCoercion(x, type), args); + } + + public static Expr BinaryTreeAnd(List terms) + { + return BinaryTreeAnd(terms, 0, terms.Count - 1); + } + + private static Expr BinaryTreeAnd(List terms, int start, int end) + { + if (start > end) + return Expr.True; + if (start == end) + return terms[start]; + if (start + 1 == end) + return Expr.And(terms[start], terms[start + 1]); + var mid = (start + end) / 2; + return Expr.And(BinaryTreeAnd(terms, start, mid), BinaryTreeAnd(terms, mid + 1, end)); + } + + public static Expr And(IEnumerable conjuncts, bool returnNullIfEmpty = false) + { + Expr result = null; + foreach (var c in conjuncts) + { + if (result != null) + { + result = LiteralExpr.And(result, c); + result.Type = Type.Bool; + } + else + { + result = c; + result.Type = Type.Bool; + } + } + if (result == null && !returnNullIfEmpty) + { + result = Expr.True; + } + return result; + } + } + [ContractClassFor(typeof(Expr))] + public abstract class ExprContracts : Expr { + public ExprContracts() :base(null, /*immutable=*/ false){ + + } + public override void Emit(TokenTextWriter wr, int contextBindingStrength, bool fragileContext) { + Contract.Requires(wr != null); + throw new NotImplementedException(); + } + public override void ComputeFreeVariables(Set freeVars) { + Contract.Requires(freeVars != null); + throw new NotImplementedException(); + } + public override Type ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + } + } + + public class LiteralExpr : Expr { + public readonly object/*!*/ Val; // false, true, a BigNum, a BigDec, or a BvConst + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Val != null); + } + + /// + /// Creates a literal expression for the boolean value "b". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, bool b, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Val = b; + Type = Type.Bool; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the integer value "v". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, BigNum v, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Val = v; + Type = Type.Int; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the real value "v". + /// + /// + /// + public LiteralExpr(IToken/*!*/ tok, BigDec v, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Val = v; + Type = Type.Real; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a literal expression for the bitvector value "v". + /// + public LiteralExpr(IToken/*!*/ tok, BigNum v, int b, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(0 <= b); + Val = new BvConst(v, b); + Type = Type.GetBvType(b); + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is LiteralExpr)) + return false; + + LiteralExpr other = (LiteralExpr)obj; + return object.Equals(this.Val, other.Val); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + return this.Val.GetHashCode(); + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + if (this.Val is bool) { + stream.Write((bool)this.Val ? "true" : "false"); // correct capitalization + } else { + stream.Write(cce.NonNull(this.Val.ToString())); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + // nothing to resolve + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + // no free variables to add + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + this.Type = ShallowType; + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + if (Val is bool) { + return Type.Bool; + } else if (Val is BigNum) { + return Type.Int; + } else if (Val is BigDec) { + return Type.Real; + } else if (Val is BvConst) { + return Type.GetBvType(((BvConst)Val).Bits); + } else { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // like, where did this value come from?! + } + } + } + + public bool IsFalse { + get { + return Val is bool && ((bool)Val) == false; + } + } + public bool IsTrue { + get { + return Val is bool && ((bool)Val) == true; + } + } + + // should be eliminated after converting everything to BigNums + private int asInt { + get { + return asBigNum.ToIntSafe; + } + } + + public bool isBigNum { + get { + return Val is BigNum; + } + } + + public BigNum asBigNum { + get { + Contract.Assert(isBigNum); + return (BigNum)cce.NonNull(Val); + } + } + + public bool isBigDec { + get { + return Val is BigDec; + } + } + + public BigDec asBigDec { + get { + Contract.Assert(isBigDec); + return (BigDec)cce.NonNull(Val); + } + } + + public bool isBool { + get { + return Val is bool; + } + } + + public bool asBool { + get { + Contract.Assert(isBool); + return (bool)cce.NonNull(Val); + } + } + + public bool isBvConst { + get { + return Val is BvConst; + } + } + + public BvConst asBvConst { + get { + Contract.Assert(isBvConst); + return (BvConst)cce.NonNull(Val); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitLiteralExpr(this); + } + } + + public class BvConst { + public readonly BigNum Value; + public readonly int Bits; + + public BvConst(BigNum v, int b) { + Contract.Assert(v.Signum >= 0); + Value = v; + Bits = b; + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return Value + "bv" + Bits; + } + + [Pure] + public string ToReadableString() { + Contract.Ensures(Contract.Result() != null); + if (Value > BigNum.FromInt(10000)) { + string val = cce.NonNull(Value.ToString("x")); + int pos = val.Length % 4; + string res = "0x" + val.Substring(0, pos); + Contract.Assert(res != null); + while (pos < val.Length) { + res += "." + val.Substring(pos, 4); + pos += 4; + } + return res + ".bv" + Bits; + } else + return ToString(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + BvConst other = obj as BvConst; + if (other == null) + return false; + + return Bits == other.Bits && Value == other.Value; + } + + [Pure] + public override int GetHashCode() { + unchecked { + return Value.GetHashCode() ^ Bits; + } + } + } + + public class IdentifierExpr : Expr { + private string _Name; + public string Name { // identifier symbol + get { + return _Name; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Name on Immutable Expr"); + + _Name = value; + } + } + private Variable _Decl; + public Variable Decl { // identifier declaration + get { + return _Decl; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Decl on Immutable Expr"); + + _Decl = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + } + + + /// + /// Creates an unresolved identifier expression. This constructor is intended to be called + /// only from within the parser; for use inside the translation, use another constructor, which + /// specifies the type of the expression. + /// + /// + /// + internal IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + _Name = name; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + /// + /// Creates an unresolved identifier expression. + /// + /// + /// + /// + public IdentifierExpr(IToken/*!*/ tok, string/*!*/ name, Type/*!*/ type, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(type != null); + _Name = name; + Type = type; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + /// + /// Creates a resolved identifier expression. + /// + /// + /// + public IdentifierExpr(IToken/*!*/ tok, Variable/*!*/ d, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(d != null); + _Name = cce.NonNull(d.Name); + _Decl = d; + Type = d.TypedIdent.Type; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is IdentifierExpr)) + return false; + + IdentifierExpr other = (IdentifierExpr)obj; + return object.Equals(this.Name, other.Name) && object.Equals(this.Decl, other.Decl); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.Name == null ? 0 : this.Name.GetHashCode(); + h ^= this.Decl == null ? 0 : this.Decl.GetHashCode(); + return h; + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + if (CommandLineOptions.Clo.PrintWithUniqueASTIds && !stream.UseForComputingChecksums) { + stream.Write("{0}^^", this.Decl == null ? "NoDecl" : "h" + this.Decl.GetHashCode()); + } + stream.Write(this, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (Decl != null) { + // already resolved, but re-resolve type just in case it came from an unresolved type + if (Type != null) { + Type = Type.ResolveType(rc); + } + return; + } + Decl = rc.LookUpVariable(Name); + if (Decl == null) { + rc.Error(this, "undeclared identifier: {0}", Name); + } else if (rc.StateMode == ResolutionContext.State.StateLess && Decl is GlobalVariable) { + rc.Error(this, "cannot refer to a global variable in this context: {0}", Name); + } + if (Type != null) { + Type = Type.ResolveType(rc); + } + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + Contract.Assume(this.Decl != null); + freeVars.Add(Decl); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + if (this.Decl != null) { + // sanity check + if (Type != null && !Type.Equals(Decl.TypedIdent.Type)) { + tc.Error(this, "internal error, shallow-type assignment was done incorrectly, {0}:{1} != {2}", + Name, Type, Decl.TypedIdent.Type); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + Type = Decl.TypedIdent.Type; + } + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + Contract.Assert(Type != null); + return Type; + } + } + + public sealed class ConstantFunApp { + private IdentifierExpr/*!*/ identifierExpr; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(identifierExpr != null); + Contract.Invariant(emptyArgs != null); + } + + public IdentifierExpr/*!*/ IdentifierExpr { + get { + Contract.Requires(IdentifierExpr != null); + return identifierExpr; + } + } + + private static IList/*!*/ emptyArgs = ArrayList.ReadOnly(cce.NonNull((IList/*!*/)new ArrayList())); + public IList/*!*/ Arguments { + get { + Contract.Ensures(Contract.Result() != null); + return emptyArgs; + } + } + + public ConstantFunApp(IdentifierExpr ie, Constant c) { + Contract.Requires(c != null); + Contract.Requires(ie != null); + this.identifierExpr = ie; + } + + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitIdentifierExpr(this); + } + } + + public class OldExpr : Expr + { + private Expr _Expr; + public Expr/*!*/ Expr { + get { + return _Expr; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Expr of an Immutable OldExpr"); + + _Expr = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr != null); + } + + public OldExpr(IToken/*!*/ tok, Expr/*!*/ expr, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(expr != null); + _Expr = expr; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is OldExpr)) + return false; + + OldExpr other = (OldExpr)obj; + return object.Equals(this.Expr, other.Expr); + } + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode (); + } + public override int ComputeHashCode() { + // FIXME: This is wrong, it's as if the OldExpr node isn't there at all + return this.Expr == null ? 0 : this.Expr.GetHashCode(); + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.Write(this, "old("); + this.Expr.Emit(stream); + stream.Write(")"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (rc.StateMode != ResolutionContext.State.Two) { + rc.Error(this, "old expressions allowed only in two-state contexts"); + } + Expr.Resolve(rc); + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + Expr.ComputeFreeVariables(freeVars); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Expr.Typecheck(tc); + Type = Expr.Type; + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Expr.ShallowType; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitOldExpr(this); + } + } + [ContractClass(typeof(IAppliableVisitorContracts<>))] + public interface IAppliableVisitor { + T Visit(UnaryOperator/*!*/ unaryOperator); + T Visit(BinaryOperator/*!*/ binaryOperator); + T Visit(FunctionCall/*!*/ functionCall); + T Visit(MapSelect/*!*/ mapSelect); + T Visit(MapStore/*!*/ mapStore); + T Visit(TypeCoercion/*!*/ typeCoercion); + T Visit(ArithmeticCoercion/*!*/ arithCoercion); + T Visit(IfThenElse/*!*/ ifThenElse); + } + [ContractClassFor(typeof(IAppliableVisitor<>))] + public abstract class IAppliableVisitorContracts : IAppliableVisitor { + + #region IAppliableVisitor Members + + public T Visit(UnaryOperator unaryOperator) { + Contract.Requires(unaryOperator != null); + throw new NotImplementedException(); + } + + public T Visit(BinaryOperator binaryOperator) { + Contract.Requires(binaryOperator != null); + throw new NotImplementedException(); + } + + public T Visit(FunctionCall functionCall) { + Contract.Requires(functionCall != null); + throw new NotImplementedException(); + } + + public T Visit(MapSelect mapSelect) { + Contract.Requires(mapSelect != null); + throw new NotImplementedException(); + } + + public T Visit(MapStore mapStore) { + Contract.Requires(mapStore != null); + throw new NotImplementedException(); + } + + public T Visit(TypeCoercion typeCoercion) { + Contract.Requires(typeCoercion != null); + throw new NotImplementedException(); + } + + public T Visit(ArithmeticCoercion arithCoercion) { + Contract.Requires(arithCoercion != null); + throw new NotImplementedException(); + } + + public T Visit(IfThenElse ifThenElse) { + Contract.Requires(ifThenElse != null); + throw new NotImplementedException(); + } + + #endregion + } + + [ContractClass(typeof(IAppliableContracts))] + public interface IAppliable { + string/*!*/ FunctionName { + get; + } + + /// + /// Emits to "stream" the operator applied to the given arguments. + /// The length of "args" can be anything that the parser allows for this appliable operator + /// (but can be nothing else). + /// + /// + /// + /// + /// + void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext); + + void Resolve(ResolutionContext/*!*/ rc, Expr/*!*/ subjectForErrorReporting); + + /// + /// Requires the object to have been properly resolved. + /// + int ArgumentCount { + get; + } + + /// + /// Typechecks the arguments "args" for the Appliable. If the arguments are + /// appropriate, returns the result type; otherwise returns null. + /// As result of the type checking, the values of type parameters of the + /// appliable can be returned (which are then stored in the NAryExpr and later + /// also used in the VCExprAST). + /// Requires the object to have been successfully resolved. + /// Requires args.Length == ArgumentCount. + /// Requires all elements of "args" to have a non-null Type field. + /// + /// + /// + Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, TypecheckingContext/*!*/ tc); + + // Contract.Requires( Microsoft.SpecSharp.Collections.Reductions.Forall{Expr! arg in args; arg.Type != null}); + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + Type/*!*/ ShallowType(IList/*!*/ args); + + T Dispatch(IAppliableVisitor/*!*/ visitor); + } + [ContractClassFor(typeof(IAppliable))] + abstract class IAppliableContracts : IAppliable { + + #region IAppliable Members + + public string FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + throw new NotImplementedException(); + } + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + Contract.Requires(args != null); + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + Contract.Requires(rc != null); + Contract.Requires(subjectForErrorReporting != null); + throw new NotImplementedException(); + } + + public int ArgumentCount { + get { + throw new NotImplementedException(); + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + Contract.Requires(args != null); + Contract.Requires(tc != null); + Contract.Ensures(Contract.ValueAtReturn(out args) != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(args.Count == Contract.OldValue(args.Count)); + throw new NotImplementedException(); + } + + public Type ShallowType(IList args) { + Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + + public T Dispatch(IAppliableVisitor visitor) { + Contract.Requires(visitor != null); + throw new NotImplementedException(); + } + + #endregion + } + + + [ContractClass(typeof(IOverloadedAppliableContracts))] + public interface IOverloadedAppliable { + void ResolveOverloading(NAryExpr/*!*/ expr); + bool DoNotResolveOverloading { get; set; } + } + [ContractClassFor(typeof(IOverloadedAppliable))] + public abstract class IOverloadedAppliableContracts : IOverloadedAppliable { + + #region IOverloadedAppliable Members + + void IOverloadedAppliable.ResolveOverloading(NAryExpr expr) { + Contract.Requires(expr != null); + throw new NotImplementedException(); + } + + public bool DoNotResolveOverloading + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + #endregion + } + + public class UnaryOperator : IAppliable { + private IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + public enum Opcode { + Neg, + Not + }; + private Opcode op; + public Opcode Op { + get { + return op; + } + } + public UnaryOperator(IToken tok, Opcode op) { + Contract.Requires(tok != null); + this.tok = tok; + this.op = op; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is UnaryOperator)) + return false; + + UnaryOperator other = (UnaryOperator)obj; + return object.Equals(this.op, other.op); + } + [Pure] + public override int GetHashCode() { + return (int)this.op; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + switch (this.op) { + case Opcode.Neg: + return "-"; + case Opcode.Not: + return "!"; + } + System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); + throw new Exception(); + } + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.SetToken(ref this.tok); + Contract.Assert(args.Count == 1); + // determine if parens are needed + int opBindingStrength = 0x70; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + stream.Write(FunctionName); + cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); + if (parensNeeded) { + stream.Write(")"); + } + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + if (rc.TriggerMode && this.op == Opcode.Not) { + rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); + } + } + + public int ArgumentCount { + get { + return 1; + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(Contract.ValueAtReturn(out args) != null); + + Contract.Assume(args.Count == 1); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + Type arg0type = cce.NonNull(cce.NonNull(args[0]).Type); + switch (this.op) { + case Opcode.Neg: + if (arg0type.Unify(Type.Int)) { + return Type.Int; + } + if (arg0type.Unify(Type.Real)) { + return Type.Real; + } + goto BAD_TYPE; + case Opcode.Not: + if (arg0type.Unify(Type.Bool)) { + return Type.Bool; + } + goto BAD_TYPE; + } + System.Diagnostics.Debug.Fail("unknown unary operator: " + op.ToString()); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + BAD_TYPE: + tc.Error(this.tok, "invalid argument type ({1}) to unary operator {0}", + this.FunctionName, arg0type); + return null; + } + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + switch (this.op) { + case Opcode.Neg: + return cce.NonNull(cce.NonNull(args[0]).Type); + case Opcode.Not: + return Type.Bool; + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // unexpected unary operator + } + } + + public object Evaluate(object argument) { + if (argument == null) { + return null; + } + switch (this.op) { + case Opcode.Neg: + if (argument is BigNum) { + return -((BigNum)argument); + } + if (argument is BigDec) { + return -((BigDec)argument); + } + break; + case Opcode.Not: + if (argument is bool) { + return !((bool)argument); + } + throw new System.InvalidOperationException("unary Not only applies to bool"); + } + return null; // unreachable + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class BinaryOperator : IAppliable, IOverloadedAppliable { + private IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + public bool DoNotResolveOverloading { get; set; } + + public enum Opcode { + Add, + Sub, + Mul, + Div, + Mod, + RealDiv, + Pow, + Eq, + Neq, + Gt, + Ge, + Lt, + Le, + And, + Or, + Imp, + Iff, + Subtype + }; + private Opcode op; + public Opcode Op { + get { + return op; + } + } + public BinaryOperator(IToken tok, Opcode op) { + Contract.Requires(tok != null); + this.tok = tok; + this.op = op; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BinaryOperator)) + return false; + + BinaryOperator other = (BinaryOperator)obj; + return object.Equals(this.op, other.op); + } + + [Pure] + public override int GetHashCode() { + return (int)this.op << 1; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + switch (this.op) { + case Opcode.Add: + return "+"; + case Opcode.Sub: + return "-"; + case Opcode.Mul: + return "*"; + case Opcode.Div: + return "div"; + case Opcode.Mod: + return "mod"; + case Opcode.RealDiv: + return "/"; + case Opcode.Pow: + return "**"; + case Opcode.Eq: + return "=="; + case Opcode.Neq: + return "!="; + case Opcode.Gt: + return ">"; + case Opcode.Ge: + return ">="; + case Opcode.Lt: + return "<"; + case Opcode.Le: + return "<="; + case Opcode.And: + return "&&"; + case Opcode.Or: + return "||"; + case Opcode.Imp: + return "==>"; + case Opcode.Iff: + return "<==>"; + case Opcode.Subtype: + return "<:"; + } + System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); + throw new Exception(); + } + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.SetToken(ref this.tok); + Contract.Assert(args.Count == 2); + // determine if parens are needed + int opBindingStrength; + bool fragileLeftContext = false; // false means "allow same binding power on left without parens" + bool fragileRightContext = false; // false means "allow same binding power on right without parens" + switch (this.op) { + case Opcode.Add: + opBindingStrength = 0x40; + break; + case Opcode.Sub: + opBindingStrength = 0x40; + fragileRightContext = true; + break; + case Opcode.Mul: + opBindingStrength = 0x50; + break; + case Opcode.Div: + opBindingStrength = 0x50; + fragileRightContext = true; + break; + case Opcode.Mod: + opBindingStrength = 0x50; + fragileRightContext = true; + break; + case Opcode.RealDiv: + opBindingStrength = 0x50; + fragileRightContext = true; + break; + case Opcode.Pow: + opBindingStrength = 0x60; + fragileRightContext = true; + break; + case Opcode.Eq: + case Opcode.Neq: + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + case Opcode.Subtype: + opBindingStrength = 0x30; + fragileLeftContext = fragileRightContext = true; + break; + case Opcode.And: + opBindingStrength = 0x20; + break; + case Opcode.Or: + opBindingStrength = 0x21; + break; + case Opcode.Imp: + opBindingStrength = 0x10; + fragileLeftContext = true; + break; + case Opcode.Iff: + opBindingStrength = 0x00; + break; + default: + System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); + opBindingStrength = -1; // to please compiler, which refuses to consider whether or not all enumeration cases have been considered! + break; + } + int opBS = opBindingStrength & 0xF0; + int ctxtBS = contextBindingStrength & 0xF0; + bool parensNeeded = opBS < ctxtBS || + (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext)); + + var pop = stream.push(FunctionName); + if (parensNeeded) { + stream.Write("("); + } + cce.NonNull(args[0]).Emit(stream, opBindingStrength, fragileLeftContext); + stream.sep(); + stream.Write(" {0} ", FunctionName); + cce.NonNull(args[1]).Emit(stream, opBindingStrength, fragileRightContext); + if (parensNeeded) { + stream.Write(")"); + } + stream.pop(pop); + } + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + if (rc.TriggerMode) { + switch (this.op) { + case Opcode.Add: + case Opcode.Sub: + case Opcode.Mul: + case Opcode.Div: + case Opcode.Mod: + case Opcode.RealDiv: + case Opcode.Pow: + case Opcode.Neq: // Neq is allowed, but not Eq + case Opcode.Subtype: + // These are fine + break; + + case Opcode.Eq: + rc.Error(subjectForErrorReporting, "equality is not allowed in triggers"); + break; + + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + rc.Error(subjectForErrorReporting, "arithmetic comparisons are not allowed in triggers"); + break; + + case Opcode.And: + case Opcode.Or: + case Opcode.Imp: + case Opcode.Iff: + rc.Error(subjectForErrorReporting, "boolean operators are not allowed in triggers"); + break; + + default: + System.Diagnostics.Debug.Fail("unknown binary operator: " + this.op.ToString()); + break; + } + } + } + public int ArgumentCount { + get { + return 2; + } + } + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(args != null); + Contract.Assert(args.Count == 2); + // the default; the only binary operator with a type parameter is equality, but right + // we don't store this parameter because it does not appear necessary + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + Expr arg0 = cce.NonNull(args[0]); + Expr arg1 = cce.NonNull(args[1]); + Type arg0type = cce.NonNull(arg0.Type); + Type arg1type = cce.NonNull(arg1.Type); + switch (this.op) { + case Opcode.Add: + case Opcode.Sub: + case Opcode.Mul: + if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { + return Type.Int; + } + if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { + return Type.Real; + } + goto BAD_TYPE; + case Opcode.Div: + case Opcode.Mod: + if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { + return Type.Int; + } + goto BAD_TYPE; + case Opcode.RealDiv: + if ((arg0type.Unify(Type.Int) || arg0type.Unify(Type.Real)) && + (arg1type.Unify(Type.Int) || arg1type.Unify(Type.Real))) { + return Type.Real; + } + goto BAD_TYPE; + case Opcode.Pow: + if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { + return Type.Real; + } + goto BAD_TYPE; + case Opcode.Eq: + case Opcode.Neq: + // Comparison is allowed if the argument types are unifiable + // (i.e., if there is any chance that the values of the arguments are + // in the same domain) + if (arg0type.Equals(arg1type)) { + // quick path + return Type.Bool; + } + List/*!*/ unifiable = new List(); + unifiable.AddRange(arg0type.FreeVariables); + unifiable.AddRange(arg1type.FreeVariables); + + if (arg0type.Unify(arg1type, unifiable, new Dictionary())) + return Type.Bool; + goto BAD_TYPE; + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + if (arg0type.Unify(Type.Int) && arg1type.Unify(Type.Int)) { + return Type.Bool; + } + if (arg0type.Unify(Type.Real) && arg1type.Unify(Type.Real)) { + return Type.Bool; + } + goto BAD_TYPE; + case Opcode.And: + case Opcode.Or: + case Opcode.Imp: + case Opcode.Iff: + if (arg0type.Unify(Type.Bool) && arg1type.Unify(Type.Bool)) { + return Type.Bool; + } + goto BAD_TYPE; + case Opcode.Subtype: + // Subtype is polymorphically typed and can compare things of + // arbitrary types (but both arguments must have the same type) + if (arg0type.Unify(arg1type)) { + return Type.Bool; + } + goto BAD_TYPE; + } + System.Diagnostics.Debug.Fail("unknown binary operator: " + op.ToString()); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + BAD_TYPE: + tc.Error(this.tok, "invalid argument types ({1} and {2}) to binary operator {0}", this.FunctionName, arg0type, arg1type); + return null; + } + + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + switch (this.op) { + case Opcode.Add: + case Opcode.Sub: + case Opcode.Mul: + return cce.NonNull(args[0]).ShallowType; + + case Opcode.Div: + case Opcode.Mod: + return Type.Int; + + case Opcode.RealDiv: + case Opcode.Pow: + return Type.Real; + + case Opcode.Eq: + case Opcode.Neq: + case Opcode.Gt: + case Opcode.Ge: + case Opcode.Lt: + case Opcode.Le: + case Opcode.And: + case Opcode.Or: + case Opcode.Imp: + case Opcode.Iff: + case Opcode.Subtype: + return Type.Bool; + + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // unexpected binary operator + } + } + + public void ResolveOverloading(NAryExpr expr) { + //Contract.Requires(expr != null); + + // immutable Expr must not be modified + if (DoNotResolveOverloading || expr.Immutable) + { + return; + } + + Expr arg0 = cce.NonNull(expr.Args[0]); + Expr arg1 = cce.NonNull(expr.Args[1]); + switch (op) { + case Opcode.Eq: + if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { + expr.Fun = new BinaryOperator(tok, Opcode.Iff); + } + break; + case Opcode.Neq: + if (arg0.Type != null && arg0.Type.IsBool && arg1.Type != null && arg1.Type.IsBool) { + expr.Fun = new BinaryOperator(tok, Opcode.Iff); + var arg1New = new NAryExpr(expr.tok, new UnaryOperator(tok, UnaryOperator.Opcode.Not), new List { arg1 }); + + // ugly ... there should be some more general approach, + // e.g., to typecheck the whole expression again + arg1New.Type = Type.Bool; + arg1New.TypeParameters = SimpleTypeParamInstantiation.EMPTY; + + expr.Args[1] = arg1New; + } + break; + } + } + + public object Evaluate(object e1, object e2) { + if (e1 == null || e2 == null) { + return null; + } + + switch (this.op) { + case Opcode.Add: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) + ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) + ((BigDec)e2); + } + break; + case Opcode.Sub: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) - ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) - ((BigDec)e2); + } + break; + case Opcode.Mul: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) * ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) * ((BigDec)e2); + } + break; + case Opcode.Div: + if (e1 is BigNum && e2 is BigNum) { + return /* TODO: right semantics? */ ((BigNum)e1) / ((BigNum)e2); + } + break; + case Opcode.Mod: + if (e1 is BigNum && e2 is BigNum) { + return /* TODO: right semantics? */ ((BigNum)e1) % ((BigNum)e2); + } + break; + case Opcode.RealDiv: + // TODO: add partial evaluation fro real division + break; + case Opcode.Pow: + // TODO: add partial evaluation fro real exponentiation + break; + case Opcode.Lt: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) < ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) < ((BigDec)e2); + } + break; + case Opcode.Le: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) <= ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) <= ((BigDec)e2); + } + break; + case Opcode.Gt: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) > ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) > ((BigDec)e2); + } + break; + case Opcode.Ge: + if (e1 is BigNum && e2 is BigNum) { + return ((BigNum)e1) >= ((BigNum)e2); + } + if (e1 is BigDec && e2 is BigDec) { + return ((BigDec)e1) >= ((BigDec)e2); + } + break; + + case Opcode.And: + if (e1 is bool && e2 is bool) { + return (bool)e1 && (bool)e2; + } + break; + case Opcode.Or: + if (e1 is bool && e2 is bool) { + return (bool)e1 || (bool)e2; + } + break; + case Opcode.Imp: + if (e1 is bool && e2 is bool) { + return !(bool)e1 || (bool)e2; + } + break; + case Opcode.Iff: + if (e1 is bool && e2 is bool) { + return e1 == e2; + } + break; + + case Opcode.Eq: + return Equals(e1, e2); + case Opcode.Neq: + return !Equals(e1, e2); + + case Opcode.Subtype: + throw new System.NotImplementedException(); + } + throw new System.InvalidOperationException("bad types to binary operator " + this.op); + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + + } + + public class FunctionCall : IAppliable { + private IdentifierExpr/*!*/ name; + public Function Func; + public FunctionCall(IdentifierExpr name) { + Contract.Requires(name != null); + this.name = name; + } + public FunctionCall(Function f) { + Contract.Requires(f != null); + this.Func = f; + this.name = new IdentifierExpr(Token.NoToken, f.Name); + + // We need set the type of this IdentifierExpr so ShallowType() works + Debug.Assert(f.OutParams.Count > 0); + this.name.Type = f.OutParams[0].TypedIdent.Type; + } + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + return this.name.Name; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + public FunctionCall createUnresolvedCopy() + { + return new FunctionCall(new IdentifierExpr(name.tok, name.Name, name.Type)); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return name.Name; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + FunctionCall fc = other as FunctionCall; + return fc != null && this.Func == fc.Func; + } + [Pure] + public override int GetHashCode() { + Contract.Assume(this.Func != null); + return Func.GetHashCode(); + } + + virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + + if (stream.UseForComputingChecksums && Func.OriginalLambdaExprAsString != null) + { + stream.Write(Func.OriginalLambdaExprAsString); + } + else + { + this.name.Emit(stream, 0xF0, false); + } + if (stream.UseForComputingChecksums) + { + var c = Func.DependencyChecksum; + if (c != null) + { + stream.Write(string.Format("[dependency_checksum:{0}]", c)); + } + } + stream.Write("("); + args.Emit(stream); + stream.Write(")"); + } + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + if (Func != null) { + // already resolved + return; + } + Func = rc.LookUpProcedure(name.Name) as Function; + if (Func == null) { + rc.Error(this.name, "use of undeclared function: {0}", name.Name); + } + else if (name.Type == null) { + // We need set the type of this IdentifierExpr so ShallowType() works + Debug.Assert(name.Type == null); + Debug.Assert(Func.OutParams.Count > 0); + name.Type = Func.OutParams[0].TypedIdent.Type; + } + } + public virtual int ArgumentCount { + get { + Contract.Assume(Func != null); // ArgumentCount requires object to be properly resolved. + return Func.InParams.Count; + } + } + public virtual Type Typecheck(IList actuals, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(actuals != null); + Contract.Ensures(Contract.ValueAtReturn(out actuals) != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Assume(this.Func != null); + Contract.Assume(actuals.Count == Func.InParams.Count); + Contract.Assume(Func.OutParams.Count == 1); + + List/*!*/ resultingTypeArgs; + List actualResultType = + Type.CheckArgumentTypes(Func.TypeParameters, + out resultingTypeArgs, + new List(Func.InParams.Select(Item => Item.TypedIdent.Type).ToArray()), + actuals, + new List(Func.OutParams.Select(Item => Item.TypedIdent.Type).ToArray()), + null, + // we need some token to report a possibly wrong number of + // arguments + actuals.Count > 0 ? cce.NonNull(actuals[0]).tok : Token.NoToken, + "application of " + name.Name, + tc); + + if (actualResultType == null) { + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } else { + Contract.Assert(actualResultType.Count == 1); + tpInstantiation = + SimpleTypeParamInstantiation.From(Func.TypeParameters, resultingTypeArgs); + return actualResultType[0]; + } + } + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + Contract.Assume(name.Type != null); + return name.Type; + } + + public virtual T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class TypeCoercion : IAppliable { + private IToken/*!*/ tok; + public Type/*!*/ Type; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + public TypeCoercion(IToken tok, Type type) { + Contract.Requires(type != null); + Contract.Requires(tok != null); + this.tok = tok; + this.Type = type; + } + + public override bool Equals(object obj) { + TypeCoercion other = obj as TypeCoercion; + if (other == null) { + return false; + } else { + return object.Equals(Type, other.Type); + } + } + + + + public + string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return ":"; + } + } + + public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + //Contract.Requires(args != null); + //Contract.Requires(stream != null); + stream.SetToken(ref this.tok); + Contract.Assert(args.Count == 1); + // determine if parens are needed + int opBindingStrength = 0x80; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) + stream.Write("("); + + cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); + stream.Write("{0} ", FunctionName); + Type.Emit(stream, 0); + + if (parensNeeded) + stream.Write(")"); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + this.Type = this.Type.ResolveType(rc); + } + + public int ArgumentCount { + get { + return 1; + } + } + + public Type Typecheck(IList/*!*/ args, + out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc) { + //Contract.Requires(args != null); + //Contract.Requires(tc != null); + Contract.Ensures(args != null); + + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + Contract.Assume(args.Count == 1); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + + if (!this.Type.Unify(cce.NonNull(cce.NonNull(args[0]).Type))) + tc.Error(this.tok, "{0} cannot be coerced to {1}", + cce.NonNull(args[0]).Type, this.Type); + return this.Type; + } + + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return this.Type; + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + + } + + public class ArithmeticCoercion : IAppliable { + public enum CoercionType { + ToInt, + ToReal + } + + private IToken/*!*/ tok; + public readonly CoercionType Coercion; + private readonly string name; + private readonly Type type; + private readonly Type argType; + private readonly int hashCode; + + public ArithmeticCoercion(IToken tok, CoercionType coercion) { + this.tok = tok; + this.Coercion = coercion; + + switch (coercion) { + case CoercionType.ToInt: + this.name = "int"; + this.type = Type.Int; + this.argType = Type.Real; + this.hashCode = 1; + break; + case CoercionType.ToReal: + this.name = "real"; + this.type = Type.Real; + this.argType = Type.Int; + this.hashCode = 2; + break; + default: + Contract.Assert(false); + break; + } + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return this.name; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object other) { + ArithmeticCoercion ac = other as ArithmeticCoercion; + return ac != null && this.Coercion == ac.Coercion; + } + + [Pure] + public override int GetHashCode() { + return this.hashCode; + } + + public string/*!*/ FunctionName { + get { + return this.name; + } + } + + public int ArgumentCount { + get { + return 1; + } + } + + virtual public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.Write(this.name); + stream.Write("("); + args.Emit(stream); + stream.Write(")"); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + } + + public virtual Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + Contract.Assert(args.Count == 1); + + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + + if (!cce.NonNull(cce.NonNull(args[0]).Type).Unify(argType)) { + tc.Error(this.tok, "argument type {0} does not match expected type {1}", cce.NonNull(args[0]).Type, this.argType); + } + + return this.type; + } + + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return this.type; + } + + public virtual T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class NAryExpr : Expr { + [Additive] + [Peer] + private IAppliable _Fun; + public IAppliable/*!*/ Fun { + get { + return _Fun; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Function used by Immutable NAryExpr"); + + _Fun = value; + } + } + private List _Args; + public IList Args { + get { + if (Immutable) + return _Args.AsReadOnly(); + else + return _Args; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change Args of Immutable NAryExpr"); + + _Args = value as List; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Fun != null); + Contract.Invariant(Args != null); + } + + + // The instantiation of type parameters that is determined during type checking. + // Which type parameters are available depends on the IAppliable + public TypeParamInstantiation TypeParameters = null; + + [Captured] + public NAryExpr(IToken/*!*/ tok, IAppliable/*!*/ fun, IList/*!*/ args, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(fun != null); + Contract.Requires(args != null); + _Fun = fun; + Contract.Assert(Contract.ForAll(0, args.Count, index => args[index] != null)); + if (immutable) { + // We need to make a new list because the client might be holding + // references to the list that they gave us which could be used to + // circumvent the immutability enforcement + _Args = new List(args); + CachedHashCode = ComputeHashCode(); + } else { + if (args is List) { + // Preserve NAryExpr's old behaviour, we take ownership of the List. + // We can only do this if the type matches + _Args = args as List; + } + else { + // Otherwise we must make a copy + _Args = new List (args); + } + } + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is NAryExpr)) + return false; + + NAryExpr other = (NAryExpr)obj; + return object.Equals(this.Fun, other.Fun) && this.Args.SequenceEqual(other.Args); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return this.CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.Fun.GetHashCode(); + // DO NOT USE Args.GetHashCode() because that uses Object.GetHashCode() which uses references + // We want structural equality + foreach (var arg in Args) { + h = (97*h) + arg.GetHashCode(); + } + return h; + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + Fun.Emit(Args, stream, contextBindingStrength, fragileContext); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Fun.Resolve(rc, this); + foreach (Expr/*!*/ e in Args) { + Contract.Assert(e != null); + e.Resolve(rc); + } + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + foreach (Expr/*!*/ e in Args) { + Contract.Assert(e != null); + e.ComputeFreeVariables(freeVars); + } + // also add the free type variables + if (TypeParameters != null) { + foreach (TypeVariable/*!*/ var in TypeParameters.FormalTypeParams) { + Contract.Assert(var != null); + foreach (TypeVariable/*!*/ w in TypeParameters[var].FreeVariables) { + Contract.Assert(w != null); + freeVars.Add(w); + } + } + } + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + int prevErrorCount = tc.ErrorCount; + foreach (Expr/*!*/ e in Args) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + if (Fun.ArgumentCount != Args.Count) { + tc.Error(this, "wrong number of arguments to function: {0} ({1} instead of {2})", + Fun.FunctionName, Args.Count, Fun.ArgumentCount); + } else if (tc.ErrorCount == prevErrorCount && + // if the type parameters are set, this node has already been + // typechecked and does not need to be checked again + TypeParameters == null) { + TypeParamInstantiation tpInsts; + Type = Fun.Typecheck(Args, out tpInsts, tc); // Make sure we pass Args so if this Expr is immutable it is protected + TypeParameters = tpInsts; + } + IOverloadedAppliable oa = Fun as IOverloadedAppliable; + if (oa != null) { + oa.ResolveOverloading(this); + } + if (Type == null) { + // set Type to some non-null value + Type = new TypeProxy(this.tok, "type_checking_error"); + } + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Fun.ShallowType(Args); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitNAryExpr(this); + } + } + + public class MapSelect : IAppliable { + + public readonly int Arity; + private readonly IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + + public MapSelect(IToken tok, int arity) { + Contract.Requires(tok != null); + this.tok = tok; + this.Arity = arity; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return "MapSelect"; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (!(obj is MapSelect)) + return false; + + MapSelect other = (MapSelect)obj; + return this.Arity == other.Arity; + } + + [Pure] + public override int GetHashCode() { + return Arity.GetHashCode() * 2823; + } + + public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + //Contract.Requires(args != null); + //Contract.Requires(stream != null); + Contract.Assume(args.Count == Arity + 1); + Emit(args, stream, contextBindingStrength, fragileContext, false); + } + + public static void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext, + bool withRhs) { + Contract.Requires(args != null); + Contract.Requires(stream != null); + const int opBindingStrength = 0x90; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + cce.NonNull(args[0]).Emit(stream, opBindingStrength, false); + stream.Write("["); + + string sep = ""; + int lastIndex = withRhs ? args.Count - 1 : args.Count; + for (int i = 1; i < lastIndex; ++i) { + stream.Write(sep); + sep = ", "; + cce.NonNull(args[i]).Emit(stream); + } + + if (withRhs) { + stream.Write(" := "); + cce.NonNull(args.Last()).Emit(stream); + } + + stream.Write("]"); + if (parensNeeded) { + stream.Write(")"); + } + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + // PR: nothing? + } + + public int ArgumentCount { + get { + return Arity + 1; + } + } + + // it is assumed that each of the arguments has already been typechecked + public static Type Typecheck(Type/*!*/ mapType, + // we just pass an Absy, because in + // the AssignCmd maps can also be + // represented by non-expressions + Absy/*!*/ map, + List/*!*/ indexes, + // the type parameters, in this context, are the parameters of the + // potentially polymorphic map type. Because it might happen that + // the whole map type is unknown and represented using a MapTypeProxy, + // the instantiations given in the following out-parameter are subject + // to change if further unifications are done. + out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName) { + Contract.Requires(mapType != null); + Contract.Requires(map != null); + Contract.Requires(indexes != null); + Contract.Requires(tc != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + mapType = mapType.Expanded; + if (mapType.IsMap && mapType.MapArity != indexes.Count) { + tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1} instead of {2}", + opName, indexes.Count, mapType.MapArity); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } else if (!mapType.Unify(new MapTypeProxy(map.tok, "select", indexes.Count))) { + tc.Error(map.tok, "{0} applied to a non-map: {1}", opName, map); + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } + mapType = TypeProxy.FollowProxy(mapType); + + if (mapType is MapType) { + MapType mt = (MapType)mapType; + return mt.CheckArgumentTypes(indexes, out tpInstantiation, + typeCheckingSubject, opName, tc); + } else { + MapTypeProxy mt = (MapTypeProxy)mapType; + return mt.CheckArgumentTypes(indexes, out tpInstantiation, + typeCheckingSubject, opName, tc); + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Assume(args.Count == Arity + 1); + + // FIXME: Wny are we passing a copy? + List actualArgs = new List(); + for (int i = 1; i < args.Count; ++i) + actualArgs.Add(args[i]); + + return Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), + actualArgs, out tpInstantiation, tc, this.tok, "map select"); + } + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + Expr a0 = cce.NonNull(args[0]); + Type a0Type = a0.ShallowType; + if (a0Type == null || !a0Type.IsMap) { + // we are unable to determine the type of the select, so just return an arbitrary type + return Type.Int; + } + MapType mapType = a0Type.AsMap; + List actualArgTypes = new List(); + for (int i = 1; i < args.Count; ++i) { + actualArgTypes.Add(cce.NonNull(args[i]).ShallowType); + } + return Type.InferValueType(mapType.TypeParameters, mapType.Arguments, mapType.Result, actualArgTypes); + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + public class MapStore : IAppliable { + + public readonly int Arity; + public readonly IToken/*!*/ tok; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(tok != null); + } + + + public MapStore(IToken tok, int arity) { + Contract.Requires(tok != null); + this.tok = tok; + this.Arity = arity; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return "MapStore"; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (!(obj is MapStore)) + return false; + + MapStore other = (MapStore)obj; + return this.Arity == other.Arity; + } + + [Pure] + public override int GetHashCode() { + return Arity.GetHashCode() * 28231; + } + + public void Emit(IList/*!*/ args, TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + //Contract.Requires(args != null); + //Contract.Requires(stream != null); + Contract.Assert(args.Count == Arity + 2); + MapSelect.Emit(args, stream, contextBindingStrength, fragileContext, true); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + // PR: nothing? + } + + public int ArgumentCount { + get { + return Arity + 2; + } + } + + // it is assumed that each of the arguments has already been typechecked + public static Type Typecheck(IList/*!*/ args, out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName) { + Contract.Requires(args != null); + Contract.Requires(tc != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + // part of the type checking works exactly as for MapSelect + List selectArgs = new List(); + for (int i = 1; i < args.Count - 1; ++i) + selectArgs.Add(args[i]); + Type resultType = + MapSelect.Typecheck(cce.NonNull(cce.NonNull(args[0]).Type), cce.NonNull(args[0]), + selectArgs, out tpInstantiation, tc, typeCheckingSubject, opName); + + // check the the rhs has the right type + if (resultType == null) { + // error messages have already been created by MapSelect.Typecheck + return null; + } + Type rhsType = cce.NonNull(cce.NonNull(args.Last()).Type); + if (!resultType.Unify(rhsType)) { + tc.Error(cce.NonNull(args.Last()).tok, + "right-hand side in {0} with wrong type: {1} (expected: {2})", + opName, rhsType, resultType); + return null; + } + + return cce.NonNull(args[0]).Type; + } + + public Type Typecheck(IList/*!*/ args, + out TypeParamInstantiation/*!*/ tpInstantiation, + TypecheckingContext/*!*/ tc) { + //Contract.Requires(args != null); + //Contract.Requires(tc != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Ensures(Contract.ValueAtReturn(out args) != null); + Contract.Assert(args.Count == Arity + 2); + return Typecheck(args, out tpInstantiation, tc, this.tok, "map store"); + } + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(args[0]).ShallowType; + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + + public class IfThenElse : IAppliable { + + private IToken/*!*/ _tok; + + public IToken/*!*/ tok + { + get + { + Contract.Ensures(Contract.Result() != null); + return this._tok; + } + set + { + Contract.Requires(value != null); + this._tok = value; + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this._tok != null); + } + + public IfThenElse(IToken tok) { + Contract.Requires(tok != null); + this._tok = tok; + } + + public string/*!*/ FunctionName { + get { + Contract.Ensures(Contract.Result() != null); + + return "if-then-else"; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (!(obj is IfThenElse)) + return false; + return true; + } + + [Pure] + public override int GetHashCode() { + return 1; + } + + public void Emit(IList args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //Contract.Requires(args != null); + stream.SetToken(this); + Contract.Assert(args.Count == 3); + stream.push(); + stream.Write("(if "); + cce.NonNull(args[0]).Emit(stream, 0x00, false); + stream.sep(); + stream.Write(" then "); + cce.NonNull(args[1]).Emit(stream, 0x00, false); + stream.sep(); + stream.Write(" else "); + cce.NonNull(args[2]).Emit(stream, 0x00, false); + stream.Write(")"); + stream.pop(); + } + + public void Resolve(ResolutionContext rc, Expr subjectForErrorReporting) { + //Contract.Requires(subjectForErrorReporting != null); + //Contract.Requires(rc != null); + // PR: nothing? + } + + public int ArgumentCount { + get { + return 3; + } + } + + public Type Typecheck(IList args, out TypeParamInstantiation tpInstantiation, TypecheckingContext tc) { + //Contract.Requires(tc != null); + //Contract.Requires(args != null); + Contract.Ensures(args != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + Contract.Assert(args.Count == 3); + // the default; the only binary operator with a type parameter is equality, but right + // we don't store this parameter because it does not appear necessary + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + Expr arg0 = cce.NonNull(args[0]); + Expr arg1 = cce.NonNull(args[1]); + Expr arg2 = cce.NonNull(args[2]); + + if (!cce.NonNull(arg0.Type).Unify(Type.Bool)) { + tc.Error(this.tok, "the first argument to if-then-else should be bool, not {0}", arg0.Type); + } else if (!cce.NonNull(arg1.Type).Unify(cce.NonNull(arg2.Type))) { + tc.Error(this.tok, "branches of if-then-else have incompatible types {0} and {1}", arg1.Type, arg2.Type); + } else { + return arg1.Type; + } + + return null; + } + + /// + /// Returns the result type of the IAppliable, supposing the argument are of the correct types. + /// + public Type ShallowType(IList args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result() != null); + return cce.NonNull(args[1]).ShallowType; + } + + public T Dispatch(IAppliableVisitor visitor) { + //Contract.Requires(visitor != null); + return visitor.Visit(this); + } + } + + + + public class CodeExpr : Expr { + public List/*!*/ LocVars; + [Rep] + public List/*!*/ Blocks; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(LocVars != null); + Contract.Invariant(cce.NonNullElements(Blocks)); + } + + public CodeExpr(List/*!*/ localVariables, List/*!*/ blocks, bool immutable=false) + : base(Token.NoToken, immutable) { + Contract.Requires(localVariables != null); + Contract.Requires(cce.NonNullElements(blocks)); + Contract.Requires(0 < blocks.Count); + LocVars = localVariables; + Blocks = blocks; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + // FIXME: This seems wrong we don't want reference equality, we want structural equality + [Pure] + public override bool Equals(object obj) + { + return base.Equals(obj); + } + + [Pure] + public override int GetHashCode() + { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + return base.GetHashCode(); + } + + + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + // Treat a BlockEexpr as if it has no free variables at all + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + //level++; + int level = 0; + stream.WriteLine(level, "|{"); + + if (this.LocVars.Count > 0) { + stream.Write(level + 1, "var "); + this.LocVars.Emit(stream, true); + stream.WriteLine(";"); + } + + foreach (Block/*!*/ b in this.Blocks) { + Contract.Assert(b != null); + b.Emit(stream, level + 1); + } + + stream.WriteLine(); + stream.WriteLine(level, "}|"); + + stream.WriteLine(); + stream.WriteLine(); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + + rc.PushVarContext(); + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Register(rc); + v.Resolve(rc); + } + + rc.PushProcedureContext(); + foreach (Block/*!*/ b in Blocks) { + Contract.Assert(b != null); + b.Register(rc); + } + + foreach (Block/*!*/ b in Blocks) { + Contract.Assert(b != null); + b.Resolve(rc); + } + + rc.PopProcedureContext(); + rc.PopVarContext(); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (Variable/*!*/ v in LocVars) { + Contract.Assert(v != null); + v.Typecheck(tc); + } + foreach (Block/*!*/ b in Blocks) { + Contract.Assert(b != null); + b.Typecheck(tc); + } + this.Type = Type.Bool; + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Type.Bool; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitCodeExpr(this); + } + } + + public class BvExtractExpr : Expr { + private /*readonly--except in StandardVisitor*/ Expr/*!*/ _Bitvector; + public Expr Bitvector { + get { + return _Bitvector; + } + set { + if (Immutable) + throw new InvalidOperationException("Cannot change BitVector field of an immutable BvExtractExpr"); + + _Bitvector = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(_Bitvector != null); + } + + public readonly int Start, End; + + public BvExtractExpr(IToken/*!*/ tok, Expr/*!*/ bv, int end, int start, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(bv != null); + _Bitvector = bv; + Start = start; + End = end; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BvExtractExpr)) + return false; + + BvExtractExpr other = (BvExtractExpr)obj; + return object.Equals(this.Bitvector, other.Bitvector) && + this.Start.Equals(other.Start) && this.End.Equals(other.End); + } + + [Pure] + public override int GetHashCode() { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.Bitvector.GetHashCode(); + h ^= Start * 17 ^ End * 13; + return h; + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + int opBindingStrength = 0x90; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + Bitvector.Emit(stream, opBindingStrength, false); + stream.Write("[" + End + ":" + Start + "]"); + if (parensNeeded) { + stream.Write(")"); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + Bitvector.Resolve(rc); + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + Bitvector.ComputeFreeVariables(freeVars); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + Bitvector.Typecheck(tc); + Contract.Assert(Bitvector.Type != null); // follows from postcondition of Expr.Typecheck + + if (Start < 0) { + tc.Error(this, "start index in extract must not be negative"); + } else if (End < 0) { + tc.Error(this, "end index in extract must not be negative"); + } else if (End < Start) { + tc.Error(this, "start index in extract must be no bigger than the end index"); + } else { + Type typeConstraint = new BvTypeProxy(this.tok, "extract", End - Start); + if (typeConstraint.Unify(Bitvector.Type)) { + Type = Type.GetBvType(End - Start); + } else { + tc.Error(this, "extract operand must be a bitvector of at least {0} bits (got {1})", End - Start, Bitvector.Type); + } + } + if (Type == null) { + Type = new TypeProxy(this.tok, "type_checking_error"); + } + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Type.GetBvType(End - Start); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvExtractExpr(this); + } + } + + public class BvConcatExpr : Expr { + private /*readonly--except in StandardVisitor*/ Expr/*!*/ _E0, _E1; + public Expr E0 { + get { + return _E0; + } + set { + if (Immutable) + throw new InvalidOperationException("Can't change E0 reference on immutable Expr"); + + _E0 = value; + } + } + public Expr E1 { + get { + return _E1; + } + set { + if (Immutable) + throw new InvalidOperationException("Can't change E1 reference on immutable Expr"); + + _E1 = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(E0 != null); + Contract.Invariant(E1 != null); + } + + + public BvConcatExpr(IToken/*!*/ tok, Expr/*!*/ e0, Expr/*!*/ e1, bool immutable=false) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + _E0 = e0; + _E1 = e1; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + if (obj == null) + return false; + if (!(obj is BvConcatExpr)) + return false; + + BvConcatExpr other = (BvConcatExpr)obj; + return object.Equals(this.E0, other.E0) && object.Equals(this.E1, other.E1); + } + + [Pure] + public override int GetHashCode() + { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + int h = this.E0.GetHashCode() ^ this.E1.GetHashCode() * 17; + return h; + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.SetToken(this); + int opBindingStrength = 0x32; + bool parensNeeded = opBindingStrength < contextBindingStrength || + (fragileContext && opBindingStrength == contextBindingStrength); + + if (parensNeeded) { + stream.Write("("); + } + E0.Emit(stream, opBindingStrength, false); + stream.Write(" ++ "); + // while this operator is associative, our incomplete axioms in int translation don't + // make much use of it, so better stick to the actual tree shape + E1.Emit(stream, opBindingStrength, true); + if (parensNeeded) { + stream.Write(")"); + } + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + E0.Resolve(rc); + E1.Resolve(rc); + } + public override void ComputeFreeVariables(Set /*Variable*/ freeVars) { + //Contract.Requires(freeVars != null); + E0.ComputeFreeVariables(freeVars); + E1.ComputeFreeVariables(freeVars); + } + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + E0.Typecheck(tc); + Contract.Assert(E0.Type != null); // follows from postcondition of Expr.Typecheck + E1.Typecheck(tc); + Contract.Assert(E1.Type != null); // follows from postcondition of Expr.Typecheck + + if (E0.Type.Unify(new BvTypeProxy(this.tok, "concat0", 0)) && E1.Type.Unify(new BvTypeProxy(this.tok, "concat1", 0))) { + Type = new BvTypeProxy(this.tok, "concat", E0.Type, E1.Type); + } else { + tc.Error(this, "++ operands need to be bitvectors (got {0}, {1})", E0.Type, E1.Type); + } + if (Type == null) { + Type = new TypeProxy(this.tok, "type_checking_error"); + } + } + + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + Type t0 = E0.ShallowType; + Type t1 = E1.ShallowType; + int len0 = t0.IsBv ? t0.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; + int len1 = t1.IsBv ? t1.BvBits : /*expression is not type correct, so just pick an arbitrary number of bits*/0; + return Type.GetBvType(len0 + len1); + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvConcatExpr(this); + } + } +} + diff --git a/Source/Core/AbsyQuant.cs b/Source/Core/AbsyQuant.cs index 2258e553..9f94490b 100644 --- a/Source/Core/AbsyQuant.cs +++ b/Source/Core/AbsyQuant.cs @@ -1,930 +1,930 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - AbsyQuant.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Collections.Generic; - using System.Linq; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - using Microsoft.Basetypes; - - using Set = GSet; - - //--------------------------------------------------------------------- - // Quantifiers and general binders - //--------------------------------------------------------------------- - - public enum BinderKind { - Forall, - Exists, - Lambda - } - [ContractClassFor(typeof(BinderExpr))] - abstract class BinderExprContracts : BinderExpr { - public override BinderKind Kind { - get { - throw new NotImplementedException(); - } - } - public BinderExprContracts():base(null,null,null,null,null,false){ - } - - public override Type ShallowType { - get { - throw new NotImplementedException(); - } - } - } - [ContractClass(typeof(BinderExprContracts))] - public abstract class BinderExpr : Expr { - public List/*!*/ TypeParameters; - public List/*!*/ Dummies; - public QKeyValue Attributes; - // FIXME: Protect the above Fields - public Expr _Body; - public Expr/*!*/ Body { - get { - return _Body; - } - set { - if (Immutable) - throw new InvalidOperationException ("Cannot change the Body of an immutable BinderExpr"); - - _Body = value; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(TypeParameters != null); - Contract.Invariant(Dummies != null); - Contract.Invariant(Body != null); - } - - public BinderExpr(IToken/*!*/ tok, List/*!*/ typeParameters, - List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable) - : base(tok, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParameters != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParameters.Count > 0); - TypeParameters = typeParameters; - Dummies = dummies; - Attributes = kv; - _Body = body; - if (immutable) - CachedHashCode = ComputeHashCode(); - } - - abstract public BinderKind Kind { - get; - } - - protected static bool CompareAttributesAndTriggers = false; - - public static bool EqualWithAttributesAndTriggers(object a, object b) { - CompareAttributesAndTriggers = true; - var res = object.Equals(a, b); - Contract.Assert(CompareAttributesAndTriggers); - CompareAttributesAndTriggers = false; - return res; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object obj) { - return BinderEquals(obj); - } - - public bool BinderEquals(object obj) { - if (obj == null) { - return false; - } - if (!(obj is BinderExpr) || - this.Kind != ((BinderExpr) obj).Kind) { - return false; - } - - var other = (BinderExpr) obj; - - return this.TypeParameters.SequenceEqual(other.TypeParameters) - && this.Dummies.SequenceEqual(other.Dummies) - && (!CompareAttributesAndTriggers || object.Equals(this.Attributes, other.Attributes)) - && object.Equals(this.Body, other.Body); - } - - [Pure] - public override int GetHashCode() - { - if (Immutable) - return CachedHashCode; - else - return ComputeHashCode(); - } - - [Pure] - public override int ComputeHashCode() { - // Note, we don't hash triggers and attributes - - // DO NOT USE Dummies.GetHashCode() because we want structurally - // identical Expr to have the same hash code **not** identical references - // to have the same hash code. - int h = 0; - foreach (var dummyVar in this.Dummies) { - h = ( 53 * h ) + dummyVar.GetHashCode(); - } - - h ^= this.Body.GetHashCode(); - - // DO NOT USE TypeParameters.GetHashCode() because we want structural - // identical Expr to have the same hash code **not** identical references - // to have the same hash code. - int h2 = 0; - foreach (var typeParam in this.TypeParameters) { - h2 = ( 97 * h2 ) + typeParam.GetHashCode(); - } - - h = h * 5 + h2; - h *= ((int)Kind + 1); - return h; - } - - protected virtual void EmitTypeHint(TokenTextWriter stream) { - Contract.Requires(stream != null); - } - - protected virtual void EmitTriggers(TokenTextWriter stream) { - Contract.Requires(stream != null); - } - - public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { - //Contract.Requires(stream != null); - stream.push(); - stream.Write(this, "({0}", Kind.ToString().ToLower()); - this.EmitTypeHint(stream); - Type.EmitOptionalTypeParams(stream, TypeParameters); - stream.Write(this, " "); - this.Dummies.Emit(stream, true); - stream.Write(" :: "); - stream.sep(); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Emit(stream); - stream.Write(" "); - } - this.EmitTriggers(stream); - stream.sep(); - - this.Body.Emit(stream); - stream.Write(")"); - stream.pop(); - } - - protected virtual void ResolveTriggers(ResolutionContext rc) { - Contract.Requires(rc != null); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - if (rc.TriggerMode) { - rc.Error(this, "quantifiers are not allowed in triggers"); - } - - int previousTypeBinderState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - - rc.PushVarContext(); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - v.Register(rc); - v.Resolve(rc); - } - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Resolve(rc); - } - this.ResolveTriggers(rc); - Body.Resolve(rc); - rc.PopVarContext(); - - // establish a canonical order of the type parameters - this.TypeParameters = Type.SortTypeParams(TypeParameters, new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray()), null); - - } finally { - rc.TypeBinderState = previousTypeBinderState; - } - } - - public override void ComputeFreeVariables(Set freeVars) { - //Contract.Requires(freeVars != null); - ComputeBinderFreeVariables(TypeParameters, Dummies, Body, Attributes, freeVars); - } - - public static void ComputeBinderFreeVariables(List typeParameters, List dummies, Expr body, QKeyValue attributes, Set freeVars) { - Contract.Requires(dummies != null); - Contract.Requires(body != null); - - foreach (var v in dummies) { - Contract.Assert(v != null); - Contract.Assert(!freeVars[v]); - } - body.ComputeFreeVariables(freeVars); - for (var a = attributes; a != null; a = a.Next) { - foreach (var o in a.Params) { - var e = o as Expr; - if (e != null) { - e.ComputeFreeVariables(freeVars); - } - } - } - foreach (var v in dummies) { - freeVars.AddRange(v.TypedIdent.Type.FreeVariables); - } - freeVars.RemoveRange(dummies); - freeVars.RemoveRange(typeParameters); - } - - protected List GetUnmentionedTypeParameters() { - Contract.Ensures(Contract.Result>() != null); - List/*!*/ dummyParameters = Type.FreeVariablesIn(new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray())); - Contract.Assert(dummyParameters != null); - List/*!*/ unmentionedParameters = new List(); - foreach (TypeVariable/*!*/ var in TypeParameters) { - Contract.Assert(var != null); - if (!dummyParameters.Contains(var)) - unmentionedParameters.Add(var); - } - return unmentionedParameters; - } - } - - public class QKeyValue : Absy { - public readonly string/*!*/ Key; - private readonly List/*!*/ _params; // each element is either a string or an Expr - - public void AddParam(object p) - { - Contract.Requires(p != null); - this._params.Add(p); - } - - public void AddParams(IEnumerable ps) - { - Contract.Requires(cce.NonNullElements(ps)); - this._params.AddRange(ps); - } - - public void ClearParams() - { - this._params.Clear(); - } - - public IList Params - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._params.AsReadOnly(); - } - } - - public QKeyValue Next; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Key != null); - Contract.Invariant(cce.NonNullElements(this._params)); - } - - public QKeyValue(IToken tok, string key, IList/*!*/ parameters, QKeyValue next) - : base(tok) { - Contract.Requires(key != null); - Contract.Requires(tok != null); - Contract.Requires(cce.NonNullElements(parameters)); - Key = key; - this._params = new List(parameters); - Next = next; - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.Write("{:"); - stream.Write(Key); - string sep = " "; - foreach (object p in Params) { - stream.Write(sep); - sep = ", "; - if (p is string) { - stream.Write("\""); - stream.Write((string)p); - stream.Write("\""); - } else { - ((Expr)p).Emit(stream); - } - } - stream.Write("}"); - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - foreach (object p in Params) { - if (p is Expr) { - ((Expr)p).Resolve(rc); - } - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (object p in Params) { - if (p is Expr) { - ((Expr)p).Typecheck(tc); - } - } - } - public void AddLast(QKeyValue other) { - Contract.Requires(other != null); - QKeyValue current = this; - while (current.Next != null) { - current = current.Next; - } - current.Next = other; - } - // Look for {:name string} in list of attributes. - [Pure] - public static string FindStringAttribute(QKeyValue kv, string name) { - Contract.Requires(name != null); - for (; kv != null; kv = kv.Next) { - if (kv.Key == name) { - if (kv.Params.Count == 1 && kv.Params[0] is string) { - return (string)kv.Params[0]; - } - } - } - return null; - } - // Look for {:name expr} in list of attributes. - public static Expr FindExprAttribute(QKeyValue kv, string name) { - Contract.Requires(name != null); - for (; kv != null; kv = kv.Next) { - if (kv.Key == name) { - if (kv.Params.Count == 1 && kv.Params[0] is Expr) { - return (Expr)kv.Params[0]; - } - } - } - return null; - } - // Return 'true' if {:name true} or {:name} is an attribute in 'kv' - public static bool FindBoolAttribute(QKeyValue kv, string name) { - Contract.Requires(name != null); - for (; kv != null; kv = kv.Next) { - if (kv.Key == name) { - return kv.Params.Count == 0 || - (kv.Params.Count == 1 && kv.Params[0] is LiteralExpr && ((LiteralExpr)kv.Params[0]).IsTrue); - } - } - return false; - } - - public static int FindIntAttribute(QKeyValue kv, string name, int defl) { - Contract.Requires(name != null); - Expr e = FindExprAttribute(kv, name); - LiteralExpr l = e as LiteralExpr; - if (l != null && l.isBigNum) - return l.asBigNum.ToIntSafe; - return defl; - } - - public override Absy Clone() { - List newParams = new List(); - foreach (object o in Params) - newParams.Add(o); - return new QKeyValue(tok, Key, newParams, (Next == null) ? null : (QKeyValue)Next.Clone()); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - return visitor.VisitQKeyValue(this); - } - - public override bool Equals(object obj) { - var other = obj as QKeyValue; - if (other == null) { - return false; - } else { - return Key == other.Key && object.Equals(Params, other.Params) && - (Next == null - ? other.Next == null - : object.Equals(Next, other.Next)); - } - } - - public override int GetHashCode() { - throw new NotImplementedException(); - } - } - - public class Trigger : Absy { - public readonly bool Pos; - [Rep] - private List/*!*/ tr; - - public IList/*!*/ Tr - { - get - { - Contract.Ensures(Contract.Result>() != null); - Contract.Ensures(Contract.Result>().Count >= 1); - Contract.Ensures(this.Pos || Contract.Result>().Count == 1); - return this.tr.AsReadOnly(); - } - set - { - Contract.Requires(value != null); - Contract.Requires(value.Count >= 1); - Contract.Requires(this.Pos || value.Count == 1); - this.tr = new List(value); - } - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(this.tr != null); - Contract.Invariant(this.tr.Count >= 1); - Contract.Invariant(Pos || this.tr.Count == 1); - } - - public Trigger Next; - - public Trigger(IToken/*!*/ tok, bool pos, IEnumerable/*!*/ tr, Trigger next = null) - : base(tok) { - Contract.Requires(tok != null); - Contract.Requires(tr != null); - Contract.Requires(tr.Count() >= 1); - Contract.Requires(pos || tr.Count() == 1); - this.Pos = pos; - this.Tr = new List(tr); - this.Next = next; - } - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - stream.SetToken(this); - Contract.Assert(this.Tr.Count >= 1); - string/*!*/ sep = Pos ? "{ " : "{:nopats "; - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - stream.Write(sep); - sep = ", "; - e.Emit(stream); - } - stream.Write(" }"); - } - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - rc.TriggerMode = true; - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - e.Resolve(rc); - - // just a variable by itself is not allowed - if (e is IdentifierExpr) { - rc.Error(e, "a matching pattern must be more than just a variable by itself: {0}", e); - } - - // the free-variable check is performed in the surrounding quantifier expression (because that's - // where the bound variables are known) - } - rc.TriggerMode = false; - } - - /// - /// Add to "freeVars" the free variables in the triggering expressions. - /// - public void ComputeFreeVariables(Set /*Variable*/ freeVars) { - Contract.Requires(freeVars != null); - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - e.ComputeFreeVariables(freeVars); - } - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - foreach (Expr/*!*/ e in this.Tr) { - Contract.Assert(e != null); - e.Typecheck(tc); - } - } - - public void AddLast(Trigger other) { - Trigger current = this; - while (current.Next != null) { - current = current.Next; - } - current.Next = other; - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTrigger(this); - } - - public override bool Equals(object obj) { - var other = obj as Trigger; - if (other == null) { - return false; - } else { - return this.Tr.SequenceEqual(other.Tr) && - (Next == null ? other.Next == null : object.Equals(Next, other.Next)); - } - } - - public override int GetHashCode() { - throw new NotImplementedException(); - } - } - - public class ForallExpr : QuantifierExpr { - public ForallExpr(IToken/*!*/ tok, List/*!*/ typeParams, - List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) - : base(tok, typeParams, dummies, kv, triggers, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParams != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParams.Count > 0); - } - public ForallExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, triggers, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - public ForallExpr(IToken tok, List dummies, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, null, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - public ForallExpr(IToken tok, List typeParams, List dummies, Expr body, bool immutable=false) - : base(tok, typeParams, dummies, null, null, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(typeParams != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count + typeParams.Count > 0); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitForallExpr(this); - } - - public override BinderKind Kind { - get { - return BinderKind.Forall; - } - } - } - - public class ExistsExpr : QuantifierExpr { - public ExistsExpr(IToken/*!*/ tok, List/*!*/ typeParams, List/*!*/ dummies, - QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) - : base(tok, typeParams, dummies, kv, triggers, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParams != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParams.Count > 0); - } - public ExistsExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, triggers, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - public ExistsExpr(IToken tok, List dummies, Expr body, bool immutable=false) - : base(tok, new List(), dummies, null, null, body, immutable) { - Contract.Requires(body != null); - Contract.Requires(dummies != null); - Contract.Requires(tok != null); - Contract.Requires(dummies.Count > 0); - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitExistsExpr(this); - } - - public override BinderKind Kind { - get { - return BinderKind.Exists; - } - } - } - - public abstract class QuantifierExpr : BinderExpr { - public Trigger Triggers; - - static int SkolemIds = -1; - public static int GetNextSkolemId() { - return System.Threading.Interlocked.Increment(ref SkolemIds); - } - - public readonly int SkolemId; - - public QuantifierExpr(IToken/*!*/ tok, List/*!*/ typeParameters, - List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable) - : base(tok, typeParameters, dummies, kv, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParameters != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParameters.Count > 0); - - Contract.Assert((this is ForallExpr) || (this is ExistsExpr)); - - Triggers = triggers; - SkolemId = GetNextSkolemId(); - } - - protected override void EmitTriggers(TokenTextWriter stream) { - //Contract.Requires(stream != null); - stream.push(); - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - tr.Emit(stream); - stream.Write(" "); - stream.sep(); - } - stream.pop(); - } - - // if the user says ( forall x :: forall y :: ... ) and specifies *no* triggers, we transform it to - // (forall x, y :: ... ) which may help the prover to pick trigger terms - // - // (Note: there used to be a different criterion here, which allowed merging when triggers were specified, which could cause prover errors due to resulting unbound variables in the triggers) - private void MergeAdjecentQuantifier() { - QuantifierExpr qbody = Body as QuantifierExpr; - if (!(qbody != null && (qbody is ForallExpr) == (this is ForallExpr) && Triggers == null)) { - return; - } - qbody.MergeAdjecentQuantifier(); - if (this.Triggers != null || qbody.Triggers != null) { - return; - } - Body = qbody.Body; - TypeParameters.AddRange(qbody.TypeParameters); - Dummies.AddRange(qbody.Dummies); - Triggers = qbody.Triggers; - if (qbody.Attributes != null) { - if (Attributes == null) { - Attributes = qbody.Attributes; - } else { - QKeyValue p = Attributes; - while (p.Next != null) { - p = p.Next; - } - p.Next = qbody.Attributes; - } - } - } - - #region never triggers - private class NeverTriggerCollector : ReadOnlyVisitor { - QuantifierExpr/*!*/ parent; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(parent != null); - } - - public NeverTriggerCollector(QuantifierExpr p) { - Contract.Requires(p != null); - parent = p; - } - - public override Expr VisitNAryExpr(NAryExpr node) { - //Contract.Requires(node != null); - Contract.Ensures(Contract.Result() != null); - FunctionCall fn = node.Fun as FunctionCall; - if (fn != null && cce.NonNull(fn.Func).NeverTrigger) { - parent.Triggers = new Trigger(fn.Func.tok, false, new List { node} , parent.Triggers); - } - return base.VisitNAryExpr(node); - } - public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) { - // don't go into quantifier expression or its triggers, since the terms in there may have more bound variables - // (note, with only the VisitBinderExpr override below, we'd still be visiting triggers, which we don't want to do) - return node; - } - public override BinderExpr VisitBinderExpr(BinderExpr node) { - // don't go into binder expression, since the terms in there may have more bound variables - return node; - } - } - - private bool neverTriggerApplied; - private void ApplyNeverTriggers() { - if (neverTriggerApplied) { - return; - } - neverTriggerApplied = true; - - for (Trigger t = Triggers; t != null; t = t.Next) { - if (t.Pos) { - return; - } - } - - NeverTriggerCollector visitor = new NeverTriggerCollector(this); - visitor.VisitExpr(Body); - } - #endregion - - protected override void ResolveTriggers(ResolutionContext rc) { - //Contract.Requires(rc != null); - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - int prevErrorCount = rc.ErrorCount; - tr.Resolve(rc); - if (prevErrorCount == rc.ErrorCount) { - // for positive triggers, make sure all bound variables are mentioned - if (tr.Pos) { - Set /*Variable*/ freeVars = new Set /*Variable*/ (); - tr.ComputeFreeVariables(freeVars); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - if (!freeVars[v]) { - rc.Error(tr, "trigger must mention all quantified variables, but does not mention: {0}", v); - } - } - } - } - } - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - int oldErrorCount = rc.ErrorCount; - - this.MergeAdjecentQuantifier(); - - base.Resolve(rc); - - if (oldErrorCount == rc.ErrorCount) { - this.ApplyNeverTriggers(); - } - } - - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Typecheck(tc); - } - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - tr.Typecheck(tc); - } - Body.Typecheck(tc); - Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck - if (!Body.Type.Unify(Type.Bool)) { - tc.Error(this, "quantifier body must be of type bool"); - } - this.Type = Type.Bool; - - // Check that type parameters occur in the types of the - // dummies, or otherwise in the triggers. This can only be - // done after typechecking - List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); - Contract.Assert(unmentionedParameters != null); - - if (unmentionedParameters.Count > 0) { - // all the type parameters that do not occur in dummy types - // have to occur in triggers - - for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { - // for positive triggers, make sure all bound variables are mentioned - if (tr.Pos) { - Set /*Variable*/ freeVars = new Set /*Variable*/ (); - tr.ComputeFreeVariables(freeVars); - foreach (TypeVariable/*!*/ v in unmentionedParameters) { - Contract.Assert(v != null); - if (!freeVars[v]) - tc.Error(tr, - "trigger does not mention {0}, which does not occur in variables types either", - v); - } - } - } - } - } - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - return Type.Bool; - } - } - - public override bool Equals(object obj) { - var other = obj as QuantifierExpr; - if (other == null) { - return false; - } else { - return this.BinderEquals(obj) && - (!CompareAttributesAndTriggers || object.Equals(Triggers, other.Triggers)); - } - } - } - - - public class LambdaExpr : BinderExpr { - public LambdaExpr(IToken/*!*/ tok, List/*!*/ typeParameters, - List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable=false) - : base(tok, typeParameters, dummies, kv, body, immutable) { - Contract.Requires(tok != null); - Contract.Requires(typeParameters != null); - Contract.Requires(dummies != null); - Contract.Requires(body != null); - Contract.Requires(dummies.Count + typeParameters.Count > 0); - } - - public override BinderKind Kind { - get { - return BinderKind.Lambda; - } - } - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - base.Resolve(rc); - } - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { - kv.Typecheck(tc); - } - Body.Typecheck(tc); - Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck - - List/*!*/ argTypes = new List(); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - argTypes.Add(v.TypedIdent.Type); - } - this.Type = new MapType(this.tok, this.TypeParameters, argTypes, Body.Type); - - // Check that type parameters occur in the types of the - // dummies, or otherwise in the triggers. This can only be - // done after typechecking - List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); - Contract.Assert(unmentionedParameters != null); - - if (unmentionedParameters.Count > 0) { - tc.Error(this, "the type variable {0} does not occur in types of the lambda parameters", unmentionedParameters[0]); - } - } - - private Type mapType; - public override Type/*!*/ ShallowType { - get { - Contract.Ensures(Contract.Result() != null); - - if (mapType == null) { - List/*!*/ argTypes = new List(); - foreach (Variable/*!*/ v in Dummies) { - Contract.Assert(v != null); - argTypes.Add(v.TypedIdent.Type); - } - mapType = new MapType(this.tok, this.TypeParameters, argTypes, Body.ShallowType); - } - - return mapType; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitLambdaExpr(this); - } - - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - AbsyQuant.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Collections.Generic; + using System.Linq; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using Set = GSet; + + //--------------------------------------------------------------------- + // Quantifiers and general binders + //--------------------------------------------------------------------- + + public enum BinderKind { + Forall, + Exists, + Lambda + } + [ContractClassFor(typeof(BinderExpr))] + abstract class BinderExprContracts : BinderExpr { + public override BinderKind Kind { + get { + throw new NotImplementedException(); + } + } + public BinderExprContracts():base(null,null,null,null,null,false){ + } + + public override Type ShallowType { + get { + throw new NotImplementedException(); + } + } + } + [ContractClass(typeof(BinderExprContracts))] + public abstract class BinderExpr : Expr { + public List/*!*/ TypeParameters; + public List/*!*/ Dummies; + public QKeyValue Attributes; + // FIXME: Protect the above Fields + public Expr _Body; + public Expr/*!*/ Body { + get { + return _Body; + } + set { + if (Immutable) + throw new InvalidOperationException ("Cannot change the Body of an immutable BinderExpr"); + + _Body = value; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(TypeParameters != null); + Contract.Invariant(Dummies != null); + Contract.Invariant(Body != null); + } + + public BinderExpr(IToken/*!*/ tok, List/*!*/ typeParameters, + List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable) + : base(tok, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParameters != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParameters.Count > 0); + TypeParameters = typeParameters; + Dummies = dummies; + Attributes = kv; + _Body = body; + if (immutable) + CachedHashCode = ComputeHashCode(); + } + + abstract public BinderKind Kind { + get; + } + + protected static bool CompareAttributesAndTriggers = false; + + public static bool EqualWithAttributesAndTriggers(object a, object b) { + CompareAttributesAndTriggers = true; + var res = object.Equals(a, b); + Contract.Assert(CompareAttributesAndTriggers); + CompareAttributesAndTriggers = false; + return res; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object obj) { + return BinderEquals(obj); + } + + public bool BinderEquals(object obj) { + if (obj == null) { + return false; + } + if (!(obj is BinderExpr) || + this.Kind != ((BinderExpr) obj).Kind) { + return false; + } + + var other = (BinderExpr) obj; + + return this.TypeParameters.SequenceEqual(other.TypeParameters) + && this.Dummies.SequenceEqual(other.Dummies) + && (!CompareAttributesAndTriggers || object.Equals(this.Attributes, other.Attributes)) + && object.Equals(this.Body, other.Body); + } + + [Pure] + public override int GetHashCode() + { + if (Immutable) + return CachedHashCode; + else + return ComputeHashCode(); + } + + [Pure] + public override int ComputeHashCode() { + // Note, we don't hash triggers and attributes + + // DO NOT USE Dummies.GetHashCode() because we want structurally + // identical Expr to have the same hash code **not** identical references + // to have the same hash code. + int h = 0; + foreach (var dummyVar in this.Dummies) { + h = ( 53 * h ) + dummyVar.GetHashCode(); + } + + h ^= this.Body.GetHashCode(); + + // DO NOT USE TypeParameters.GetHashCode() because we want structural + // identical Expr to have the same hash code **not** identical references + // to have the same hash code. + int h2 = 0; + foreach (var typeParam in this.TypeParameters) { + h2 = ( 97 * h2 ) + typeParam.GetHashCode(); + } + + h = h * 5 + h2; + h *= ((int)Kind + 1); + return h; + } + + protected virtual void EmitTypeHint(TokenTextWriter stream) { + Contract.Requires(stream != null); + } + + protected virtual void EmitTriggers(TokenTextWriter stream) { + Contract.Requires(stream != null); + } + + public override void Emit(TokenTextWriter stream, int contextBindingStrength, bool fragileContext) { + //Contract.Requires(stream != null); + stream.push(); + stream.Write(this, "({0}", Kind.ToString().ToLower()); + this.EmitTypeHint(stream); + Type.EmitOptionalTypeParams(stream, TypeParameters); + stream.Write(this, " "); + this.Dummies.Emit(stream, true); + stream.Write(" :: "); + stream.sep(); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Emit(stream); + stream.Write(" "); + } + this.EmitTriggers(stream); + stream.sep(); + + this.Body.Emit(stream); + stream.Write(")"); + stream.pop(); + } + + protected virtual void ResolveTriggers(ResolutionContext rc) { + Contract.Requires(rc != null); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + if (rc.TriggerMode) { + rc.Error(this, "quantifiers are not allowed in triggers"); + } + + int previousTypeBinderState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + + rc.PushVarContext(); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + v.Register(rc); + v.Resolve(rc); + } + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Resolve(rc); + } + this.ResolveTriggers(rc); + Body.Resolve(rc); + rc.PopVarContext(); + + // establish a canonical order of the type parameters + this.TypeParameters = Type.SortTypeParams(TypeParameters, new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray()), null); + + } finally { + rc.TypeBinderState = previousTypeBinderState; + } + } + + public override void ComputeFreeVariables(Set freeVars) { + //Contract.Requires(freeVars != null); + ComputeBinderFreeVariables(TypeParameters, Dummies, Body, Attributes, freeVars); + } + + public static void ComputeBinderFreeVariables(List typeParameters, List dummies, Expr body, QKeyValue attributes, Set freeVars) { + Contract.Requires(dummies != null); + Contract.Requires(body != null); + + foreach (var v in dummies) { + Contract.Assert(v != null); + Contract.Assert(!freeVars[v]); + } + body.ComputeFreeVariables(freeVars); + for (var a = attributes; a != null; a = a.Next) { + foreach (var o in a.Params) { + var e = o as Expr; + if (e != null) { + e.ComputeFreeVariables(freeVars); + } + } + } + foreach (var v in dummies) { + freeVars.AddRange(v.TypedIdent.Type.FreeVariables); + } + freeVars.RemoveRange(dummies); + freeVars.RemoveRange(typeParameters); + } + + protected List GetUnmentionedTypeParameters() { + Contract.Ensures(Contract.Result>() != null); + List/*!*/ dummyParameters = Type.FreeVariablesIn(new List(Dummies.Select(Item => Item.TypedIdent.Type).ToArray())); + Contract.Assert(dummyParameters != null); + List/*!*/ unmentionedParameters = new List(); + foreach (TypeVariable/*!*/ var in TypeParameters) { + Contract.Assert(var != null); + if (!dummyParameters.Contains(var)) + unmentionedParameters.Add(var); + } + return unmentionedParameters; + } + } + + public class QKeyValue : Absy { + public readonly string/*!*/ Key; + private readonly List/*!*/ _params; // each element is either a string or an Expr + + public void AddParam(object p) + { + Contract.Requires(p != null); + this._params.Add(p); + } + + public void AddParams(IEnumerable ps) + { + Contract.Requires(cce.NonNullElements(ps)); + this._params.AddRange(ps); + } + + public void ClearParams() + { + this._params.Clear(); + } + + public IList Params + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Contract.Ensures(Contract.Result>().IsReadOnly); + return this._params.AsReadOnly(); + } + } + + public QKeyValue Next; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Key != null); + Contract.Invariant(cce.NonNullElements(this._params)); + } + + public QKeyValue(IToken tok, string key, IList/*!*/ parameters, QKeyValue next) + : base(tok) { + Contract.Requires(key != null); + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(parameters)); + Key = key; + this._params = new List(parameters); + Next = next; + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.Write("{:"); + stream.Write(Key); + string sep = " "; + foreach (object p in Params) { + stream.Write(sep); + sep = ", "; + if (p is string) { + stream.Write("\""); + stream.Write((string)p); + stream.Write("\""); + } else { + ((Expr)p).Emit(stream); + } + } + stream.Write("}"); + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + foreach (object p in Params) { + if (p is Expr) { + ((Expr)p).Resolve(rc); + } + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (object p in Params) { + if (p is Expr) { + ((Expr)p).Typecheck(tc); + } + } + } + public void AddLast(QKeyValue other) { + Contract.Requires(other != null); + QKeyValue current = this; + while (current.Next != null) { + current = current.Next; + } + current.Next = other; + } + // Look for {:name string} in list of attributes. + [Pure] + public static string FindStringAttribute(QKeyValue kv, string name) { + Contract.Requires(name != null); + for (; kv != null; kv = kv.Next) { + if (kv.Key == name) { + if (kv.Params.Count == 1 && kv.Params[0] is string) { + return (string)kv.Params[0]; + } + } + } + return null; + } + // Look for {:name expr} in list of attributes. + public static Expr FindExprAttribute(QKeyValue kv, string name) { + Contract.Requires(name != null); + for (; kv != null; kv = kv.Next) { + if (kv.Key == name) { + if (kv.Params.Count == 1 && kv.Params[0] is Expr) { + return (Expr)kv.Params[0]; + } + } + } + return null; + } + // Return 'true' if {:name true} or {:name} is an attribute in 'kv' + public static bool FindBoolAttribute(QKeyValue kv, string name) { + Contract.Requires(name != null); + for (; kv != null; kv = kv.Next) { + if (kv.Key == name) { + return kv.Params.Count == 0 || + (kv.Params.Count == 1 && kv.Params[0] is LiteralExpr && ((LiteralExpr)kv.Params[0]).IsTrue); + } + } + return false; + } + + public static int FindIntAttribute(QKeyValue kv, string name, int defl) { + Contract.Requires(name != null); + Expr e = FindExprAttribute(kv, name); + LiteralExpr l = e as LiteralExpr; + if (l != null && l.isBigNum) + return l.asBigNum.ToIntSafe; + return defl; + } + + public override Absy Clone() { + List newParams = new List(); + foreach (object o in Params) + newParams.Add(o); + return new QKeyValue(tok, Key, newParams, (Next == null) ? null : (QKeyValue)Next.Clone()); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + return visitor.VisitQKeyValue(this); + } + + public override bool Equals(object obj) { + var other = obj as QKeyValue; + if (other == null) { + return false; + } else { + return Key == other.Key && object.Equals(Params, other.Params) && + (Next == null + ? other.Next == null + : object.Equals(Next, other.Next)); + } + } + + public override int GetHashCode() { + throw new NotImplementedException(); + } + } + + public class Trigger : Absy { + public readonly bool Pos; + [Rep] + private List/*!*/ tr; + + public IList/*!*/ Tr + { + get + { + Contract.Ensures(Contract.Result>() != null); + Contract.Ensures(Contract.Result>().Count >= 1); + Contract.Ensures(this.Pos || Contract.Result>().Count == 1); + return this.tr.AsReadOnly(); + } + set + { + Contract.Requires(value != null); + Contract.Requires(value.Count >= 1); + Contract.Requires(this.Pos || value.Count == 1); + this.tr = new List(value); + } + } + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(this.tr != null); + Contract.Invariant(this.tr.Count >= 1); + Contract.Invariant(Pos || this.tr.Count == 1); + } + + public Trigger Next; + + public Trigger(IToken/*!*/ tok, bool pos, IEnumerable/*!*/ tr, Trigger next = null) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(tr != null); + Contract.Requires(tr.Count() >= 1); + Contract.Requires(pos || tr.Count() == 1); + this.Pos = pos; + this.Tr = new List(tr); + this.Next = next; + } + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + stream.SetToken(this); + Contract.Assert(this.Tr.Count >= 1); + string/*!*/ sep = Pos ? "{ " : "{:nopats "; + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + stream.Write(sep); + sep = ", "; + e.Emit(stream); + } + stream.Write(" }"); + } + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + rc.TriggerMode = true; + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + e.Resolve(rc); + + // just a variable by itself is not allowed + if (e is IdentifierExpr) { + rc.Error(e, "a matching pattern must be more than just a variable by itself: {0}", e); + } + + // the free-variable check is performed in the surrounding quantifier expression (because that's + // where the bound variables are known) + } + rc.TriggerMode = false; + } + + /// + /// Add to "freeVars" the free variables in the triggering expressions. + /// + public void ComputeFreeVariables(Set /*Variable*/ freeVars) { + Contract.Requires(freeVars != null); + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + e.ComputeFreeVariables(freeVars); + } + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + foreach (Expr/*!*/ e in this.Tr) { + Contract.Assert(e != null); + e.Typecheck(tc); + } + } + + public void AddLast(Trigger other) { + Trigger current = this; + while (current.Next != null) { + current = current.Next; + } + current.Next = other; + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTrigger(this); + } + + public override bool Equals(object obj) { + var other = obj as Trigger; + if (other == null) { + return false; + } else { + return this.Tr.SequenceEqual(other.Tr) && + (Next == null ? other.Next == null : object.Equals(Next, other.Next)); + } + } + + public override int GetHashCode() { + throw new NotImplementedException(); + } + } + + public class ForallExpr : QuantifierExpr { + public ForallExpr(IToken/*!*/ tok, List/*!*/ typeParams, + List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) + : base(tok, typeParams, dummies, kv, triggers, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParams != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParams.Count > 0); + } + public ForallExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, triggers, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + public ForallExpr(IToken tok, List dummies, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, null, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + public ForallExpr(IToken tok, List typeParams, List dummies, Expr body, bool immutable=false) + : base(tok, typeParams, dummies, null, null, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(typeParams != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count + typeParams.Count > 0); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitForallExpr(this); + } + + public override BinderKind Kind { + get { + return BinderKind.Forall; + } + } + } + + public class ExistsExpr : QuantifierExpr { + public ExistsExpr(IToken/*!*/ tok, List/*!*/ typeParams, List/*!*/ dummies, + QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false) + : base(tok, typeParams, dummies, kv, triggers, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParams != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParams.Count > 0); + } + public ExistsExpr(IToken tok, List dummies, Trigger triggers, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, triggers, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + public ExistsExpr(IToken tok, List dummies, Expr body, bool immutable=false) + : base(tok, new List(), dummies, null, null, body, immutable) { + Contract.Requires(body != null); + Contract.Requires(dummies != null); + Contract.Requires(tok != null); + Contract.Requires(dummies.Count > 0); + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitExistsExpr(this); + } + + public override BinderKind Kind { + get { + return BinderKind.Exists; + } + } + } + + public abstract class QuantifierExpr : BinderExpr { + public Trigger Triggers; + + static int SkolemIds = -1; + public static int GetNextSkolemId() { + return System.Threading.Interlocked.Increment(ref SkolemIds); + } + + public readonly int SkolemId; + + public QuantifierExpr(IToken/*!*/ tok, List/*!*/ typeParameters, + List/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable) + : base(tok, typeParameters, dummies, kv, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParameters != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParameters.Count > 0); + + Contract.Assert((this is ForallExpr) || (this is ExistsExpr)); + + Triggers = triggers; + SkolemId = GetNextSkolemId(); + } + + protected override void EmitTriggers(TokenTextWriter stream) { + //Contract.Requires(stream != null); + stream.push(); + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + tr.Emit(stream); + stream.Write(" "); + stream.sep(); + } + stream.pop(); + } + + // if the user says ( forall x :: forall y :: ... ) and specifies *no* triggers, we transform it to + // (forall x, y :: ... ) which may help the prover to pick trigger terms + // + // (Note: there used to be a different criterion here, which allowed merging when triggers were specified, which could cause prover errors due to resulting unbound variables in the triggers) + private void MergeAdjecentQuantifier() { + QuantifierExpr qbody = Body as QuantifierExpr; + if (!(qbody != null && (qbody is ForallExpr) == (this is ForallExpr) && Triggers == null)) { + return; + } + qbody.MergeAdjecentQuantifier(); + if (this.Triggers != null || qbody.Triggers != null) { + return; + } + Body = qbody.Body; + TypeParameters.AddRange(qbody.TypeParameters); + Dummies.AddRange(qbody.Dummies); + Triggers = qbody.Triggers; + if (qbody.Attributes != null) { + if (Attributes == null) { + Attributes = qbody.Attributes; + } else { + QKeyValue p = Attributes; + while (p.Next != null) { + p = p.Next; + } + p.Next = qbody.Attributes; + } + } + } + + #region never triggers + private class NeverTriggerCollector : ReadOnlyVisitor { + QuantifierExpr/*!*/ parent; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(parent != null); + } + + public NeverTriggerCollector(QuantifierExpr p) { + Contract.Requires(p != null); + parent = p; + } + + public override Expr VisitNAryExpr(NAryExpr node) { + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result() != null); + FunctionCall fn = node.Fun as FunctionCall; + if (fn != null && cce.NonNull(fn.Func).NeverTrigger) { + parent.Triggers = new Trigger(fn.Func.tok, false, new List { node} , parent.Triggers); + } + return base.VisitNAryExpr(node); + } + public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) { + // don't go into quantifier expression or its triggers, since the terms in there may have more bound variables + // (note, with only the VisitBinderExpr override below, we'd still be visiting triggers, which we don't want to do) + return node; + } + public override BinderExpr VisitBinderExpr(BinderExpr node) { + // don't go into binder expression, since the terms in there may have more bound variables + return node; + } + } + + private bool neverTriggerApplied; + private void ApplyNeverTriggers() { + if (neverTriggerApplied) { + return; + } + neverTriggerApplied = true; + + for (Trigger t = Triggers; t != null; t = t.Next) { + if (t.Pos) { + return; + } + } + + NeverTriggerCollector visitor = new NeverTriggerCollector(this); + visitor.VisitExpr(Body); + } + #endregion + + protected override void ResolveTriggers(ResolutionContext rc) { + //Contract.Requires(rc != null); + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + int prevErrorCount = rc.ErrorCount; + tr.Resolve(rc); + if (prevErrorCount == rc.ErrorCount) { + // for positive triggers, make sure all bound variables are mentioned + if (tr.Pos) { + Set /*Variable*/ freeVars = new Set /*Variable*/ (); + tr.ComputeFreeVariables(freeVars); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + if (!freeVars[v]) { + rc.Error(tr, "trigger must mention all quantified variables, but does not mention: {0}", v); + } + } + } + } + } + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + int oldErrorCount = rc.ErrorCount; + + this.MergeAdjecentQuantifier(); + + base.Resolve(rc); + + if (oldErrorCount == rc.ErrorCount) { + this.ApplyNeverTriggers(); + } + } + + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Typecheck(tc); + } + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + tr.Typecheck(tc); + } + Body.Typecheck(tc); + Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck + if (!Body.Type.Unify(Type.Bool)) { + tc.Error(this, "quantifier body must be of type bool"); + } + this.Type = Type.Bool; + + // Check that type parameters occur in the types of the + // dummies, or otherwise in the triggers. This can only be + // done after typechecking + List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); + Contract.Assert(unmentionedParameters != null); + + if (unmentionedParameters.Count > 0) { + // all the type parameters that do not occur in dummy types + // have to occur in triggers + + for (Trigger tr = this.Triggers; tr != null; tr = tr.Next) { + // for positive triggers, make sure all bound variables are mentioned + if (tr.Pos) { + Set /*Variable*/ freeVars = new Set /*Variable*/ (); + tr.ComputeFreeVariables(freeVars); + foreach (TypeVariable/*!*/ v in unmentionedParameters) { + Contract.Assert(v != null); + if (!freeVars[v]) + tc.Error(tr, + "trigger does not mention {0}, which does not occur in variables types either", + v); + } + } + } + } + } + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + return Type.Bool; + } + } + + public override bool Equals(object obj) { + var other = obj as QuantifierExpr; + if (other == null) { + return false; + } else { + return this.BinderEquals(obj) && + (!CompareAttributesAndTriggers || object.Equals(Triggers, other.Triggers)); + } + } + } + + + public class LambdaExpr : BinderExpr { + public LambdaExpr(IToken/*!*/ tok, List/*!*/ typeParameters, + List/*!*/ dummies, QKeyValue kv, Expr/*!*/ body, bool immutable=false) + : base(tok, typeParameters, dummies, kv, body, immutable) { + Contract.Requires(tok != null); + Contract.Requires(typeParameters != null); + Contract.Requires(dummies != null); + Contract.Requires(body != null); + Contract.Requires(dummies.Count + typeParameters.Count > 0); + } + + public override BinderKind Kind { + get { + return BinderKind.Lambda; + } + } + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + base.Resolve(rc); + } + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + for (QKeyValue kv = this.Attributes; kv != null; kv = kv.Next) { + kv.Typecheck(tc); + } + Body.Typecheck(tc); + Contract.Assert(Body.Type != null); // follows from postcondition of Expr.Typecheck + + List/*!*/ argTypes = new List(); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + argTypes.Add(v.TypedIdent.Type); + } + this.Type = new MapType(this.tok, this.TypeParameters, argTypes, Body.Type); + + // Check that type parameters occur in the types of the + // dummies, or otherwise in the triggers. This can only be + // done after typechecking + List/*!*/ unmentionedParameters = GetUnmentionedTypeParameters(); + Contract.Assert(unmentionedParameters != null); + + if (unmentionedParameters.Count > 0) { + tc.Error(this, "the type variable {0} does not occur in types of the lambda parameters", unmentionedParameters[0]); + } + } + + private Type mapType; + public override Type/*!*/ ShallowType { + get { + Contract.Ensures(Contract.Result() != null); + + if (mapType == null) { + List/*!*/ argTypes = new List(); + foreach (Variable/*!*/ v in Dummies) { + Contract.Assert(v != null); + argTypes.Add(v.TypedIdent.Type); + } + mapType = new MapType(this.tok, this.TypeParameters, argTypes, Body.ShallowType); + } + + return mapType; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitLambdaExpr(this); + } + + } +} diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs index 97309155..2953f15e 100644 --- a/Source/Core/AbsyType.cs +++ b/Source/Core/AbsyType.cs @@ -1,3697 +1,3697 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------- -// BoogiePL - Absy.cs -//--------------------------------------------------------------------------------------------- - -namespace Microsoft.Boogie { - using System; - using System.Collections; - using System.Diagnostics; - using System.Linq; - using System.Collections.Generic; - using Microsoft.Boogie.AbstractInterpretation; - using System.Diagnostics.Contracts; - - //===================================================================== - //--------------------------------------------------------------------- - // Types - [ContractClass(typeof(TypeContracts))] - public abstract class Type : Absy { - public Type(IToken/*!*/ token) - : base(token) { - Contract.Requires(token != null); - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. Applying Clone to a type will return - // a type in which all bound variables have been replaced with new - // variables, whereas free variables have not changed - - public override Absy Clone() { - Contract.Ensures(Contract.Result() != null); - return this.Clone(new Dictionary()); - } - - public abstract Type/*!*/ Clone(IDictionary/*!*/ varMap); - - /// - /// Clones the type, but only syntactically. Anything resolved in the source - /// type is left unresolved (that is, with just the name) in the destination type. - /// - public abstract Type/*!*/ CloneUnresolved(); - - //----------- Linearisation ---------------------------------- - - public void Emit(TokenTextWriter stream) { - Contract.Requires(stream != null); - this.Emit(stream, 0); - } - - public abstract void Emit(TokenTextWriter/*!*/ stream, int contextBindingStrength); - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/false, /*pretty=*/ false)) { - this.Emit(stream); - } - return buffer.ToString(); - } - - //----------- Equality ---------------------------------- - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (ReferenceEquals(this, that)) - return true; - Type thatType = that as Type; - return thatType != null && this.Equals(thatType, - new List(), - new List()); - } - - [Pure] - public abstract bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables); - - // used to skip leading type annotations (subexpressions of the - // resulting type might still contain annotations) - internal virtual Type/*!*/ Expanded { - get { - Contract.Ensures(Contract.Result() != null); - - return this; - } - } - - //----------- Unification of types ----------- - - /// - /// Add a constraint that this==that, if possible, and return true. - /// If not possible, return false (which may have added some partial constraints). - /// No error is printed. - /// - public bool Unify(Type that) { - Contract.Requires(that != null); - return Unify(that, new List(), new Dictionary()); - } - - public abstract bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier); - - - [Pure] - public static bool IsIdempotent(IDictionary/*!*/ unifier) { - Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); - return unifier.Values.All(val => val.FreeVariables.All(var => !unifier.ContainsKey(var))); - } - - -#if OLD_UNIFICATION - // Compute a most general unification of two types. null is returned if - // no such unifier exists. The unifier is not allowed to subtitute any - // type variables other than the ones in "unifiableVariables" - public IDictionary Unify(Type! that, - List! unifiableVariables) { - Dictionary! result = new Dictionary (); - try { - this.Unify(that, unifiableVariables, - new List (), new List (), result); - } catch (UnificationFailedException) { - return null; - } - return result; - } - - // Compute an idempotent most general unifier and add the result to the argument - // unifier. The result is true iff the unification succeeded - public bool Unify(Type! that, - List! unifiableVariables, - // given mappings that need to be taken into account - // the old unifier has to be idempotent as well - IDictionary! unifier) - { - Contract.Requires(Contract.ForAll(unifier.Keys , key=> unifiableVariables.Has(key))); - Contract.Requires(IsIdempotent(unifier)); - try { - this.Unify(that, unifiableVariables, - new List (), new List (), unifier); - } catch (UnificationFailedException) { - return false; - } - return true; - } - - public abstract void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary! result); -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public abstract Type/*!*/ Substitute(IDictionary/*!*/ subst); - - //----------- Hashcodes ---------------------------------- - - // Hack to be able to access the hashcode of superclasses further up - // (from the subclasses of this class) - [Pure] - protected int GetBaseHashCode() { - return base.GetHashCode(); - } - - [Pure] - public override int GetHashCode() { - return this.GetHashCode(new List()); - } - - [Pure] - public abstract int GetHashCode(List/*!*/ boundVariables); - - //----------- Resolution ---------------------------------- - - public override void Resolve(ResolutionContext rc) { - //Contract.Requires(rc != null); - System.Diagnostics.Debug.Fail("Type.Resolve should never be called." + - " Use Type.ResolveType instead"); - } - - public abstract Type/*!*/ ResolveType(ResolutionContext/*!*/ rc); - - public override void Typecheck(TypecheckingContext tc) { - //Contract.Requires(tc != null); - System.Diagnostics.Debug.Fail("Type.Typecheck should never be called"); - } - - // determine the free variables in a type, in the order in which the variables occur - public abstract List/*!*/ FreeVariables { - get; - } - - // determine the free type proxies in a type, in the order in which they occur - public abstract List/*!*/ FreeProxies { - get; - } - - protected static void AppendWithoutDups(List a, List b) { - Contract.Requires(b != null); - Contract.Requires(a != null); - foreach (A x in b) - if (!a.Contains(x)) - a.Add(x); - } - - public bool IsClosed { - get { - return FreeVariables.Count == 0; - } - } - - //----------- Getters/Issers ---------------------------------- - - // the following methods should be used instead of simple casts or the - // C# "is" operator, because they handle type synonym annotations and - // type proxies correctly - - public virtual bool IsBasic { - get { - return false; - } - } - public virtual bool IsInt { - get { - return false; - } - } - public virtual bool IsReal { - get { - return false; - } - } - public virtual bool IsBool { - get { - return false; - } - } - - public virtual bool IsVariable { - get { - return false; - } - } - public virtual TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsVariable should never be called - } - } - public virtual bool IsCtor { - get { - return false; - } - } - public virtual CtorType/*!*/ AsCtor { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsCtor should never be called - } - } - public virtual bool IsMap { - get { - return false; - } - } - public virtual MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsMap should never be called - } - } - public virtual int MapArity { - get { - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.MapArity should never be called - } - } - public virtual bool IsUnresolved { - get { - return false; - } - } - public virtual UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.AsUnresolved should never be called - } - } - - public virtual bool IsBv { - get { - return false; - } - } - public virtual int BvBits { - get { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // Type.BvBits should never be called - } - } - - public static readonly Type/*!*/ Int = new BasicType(SimpleType.Int); - public static readonly Type/*!*/ Real = new BasicType(SimpleType.Real); - public static readonly Type/*!*/ Bool = new BasicType(SimpleType.Bool); - private static BvType[] bvtypeCache; - - static public BvType GetBvType(int sz) { - Contract.Requires(0 <= sz); - Contract.Ensures(Contract.Result() != null); - - if (bvtypeCache == null) { - bvtypeCache = new BvType[128]; - } - if (sz < bvtypeCache.Length) { - BvType t = bvtypeCache[sz]; - if (t == null) { - t = new BvType(sz); - bvtypeCache[sz] = t; - } - return t; - } else { - return new BvType(sz); - } - } - - //------------ Match formal argument types on actual argument types - //------------ and return the resulting substitution of type variables - -#if OLD_UNIFICATION - public static IDictionary! - MatchArgumentTypes(List! typeParams, - List! formalArgs, - List! actualArgs, - List formalOuts, - List actualOuts, - string! opName, - TypecheckingContext! tc) - { - Contract.Requires(formalArgs.Length == actualArgs.Length); - Contract.Requires(formalOuts == null <==> actualOuts == null); - Contract.Requires(formalOuts != null ==> formalOuts.Length == actualOuts.Length); - List! boundVarSeq0 = new List (); - List! boundVarSeq1 = new List (); - Dictionary! subst = new Dictionary(); - - for (int i = 0; i < formalArgs.Length; ++i) { - try { - Type! actualType = cce.NonNull((!)actualArgs[i]).Type; - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(forall{TypeVariable! var in typeParams); - !actualType.FreeVariables.Has(var)}; - formalArgs[i].Unify(actualType, - typeParams, - boundVarSeq0, boundVarSeq1, - subst); - } catch (UnificationFailedException) { - tc.Error(actualArgs[i], - "invalid type for argument {0} in {1}: {2} (expected: {3})", - i, opName, actualArgs[i].Type, - // we insert the type parameters that have already been - // chosen to get a more precise error message - formalArgs[i].Substitute(subst)); - // the bound variable sequences should be empty ... - // so that we can continue with the unification - Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); - } - } - - if (formalOuts != null) { - for (int i = 0; i < formalOuts.Length; ++i) { - try { - Type! actualType = cce.NonNull((!)actualOuts[i]).Type; - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(forall{TypeVariable! var in typeParams); - !actualType.FreeVariables.Has(var)}; - formalOuts[i].Unify(actualType, - typeParams, - boundVarSeq0, boundVarSeq1, - subst); - } catch (UnificationFailedException) { - tc.Error(actualOuts[i], - "invalid type for result {0} in {1}: {2} (expected: {3})", - i, opName, actualOuts[i].Type, - // we insert the type parameters that have already been - // chosen to get a more precise error message - formalOuts[i].Substitute(subst)); - // the bound variable sequences should be empty ... - // so that we can continue with the unification - Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); - } - } - } - - // we only allow type parameters to be substituted - Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); - - return subst; - } -#else - public static IDictionary/*!*/ - MatchArgumentTypes(List/*!*/ typeParams, - List/*!*/ formalArgs, - IList/*!*/ actualArgs, - List formalOuts, - List actualOuts, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) { - Contract.Requires(typeParams != null); - Contract.Requires(formalArgs != null); - Contract.Requires(actualArgs != null); - Contract.Requires(opName != null); - Contract.Requires(tc != null); - Contract.Requires(formalArgs.Count == actualArgs.Count); - Contract.Requires((formalOuts == null) == (actualOuts == null)); - Contract.Requires(formalOuts == null || formalOuts.Count == cce.NonNull(actualOuts).Count); - Contract.Requires(tc == null || opName != null);//Redundant - Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); - - // requires "actualArgs" and "actualOuts" to have been type checked - - Dictionary subst = new Dictionary(); - foreach (TypeVariable/*!*/ tv in typeParams) { - Contract.Assert(tv != null); - TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); - subst.Add(tv, proxy); - } - - for (int i = 0; i < formalArgs.Count; i++) { - Type formal = formalArgs[i].Substitute(subst); - Type actual = cce.NonNull(cce.NonNull(actualArgs[i]).Type); - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); - - if (!formal.Unify(actual)) { - Contract.Assume(tc != null); // caller expected no errors - Contract.Assert(opName != null); // follows from precondition - tc.Error(cce.NonNull(actualArgs[i]), - "invalid type for argument {0} in {1}: {2} (expected: {3})", - i, opName, actual, formalArgs[i]); - } - } - - if (formalOuts != null) { - for (int i = 0; i < formalOuts.Count; ++i) { - Type formal = formalOuts[i].Substitute(subst); - Type actual = cce.NonNull(cce.NonNull(actualOuts)[i].Type); - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !actual.FreeVariables.Contains(typeParams[var]))); - - if (!formal.Unify(actual)) { - Contract.Assume(tc != null); // caller expected no errors - Contract.Assert(opName != null); // follows from precondition - tc.Error(actualOuts[i], - "invalid type for out-parameter {0} in {1}: {2} (expected: {3})", - i, opName, actual, formal); - } - } - } - - return subst; - } -#endif - - //------------ Match formal argument types of a function or map - //------------ on concrete types, substitute the result into the - //------------ result type. Null is returned for type errors - - public static List CheckArgumentTypes(List/*!*/ typeParams, - out List/*!*/ actualTypeParams, - List/*!*/ formalIns, - IList/*!*/ actualIns, - List/*!*/ formalOuts, - List actualOuts, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) - // requires "actualIns" and "actualOuts" to have been type checked - { - Contract.Requires(typeParams != null); - - Contract.Requires(formalIns != null); - Contract.Requires(formalOuts != null); - Contract.Requires(actualIns != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null);Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out actualTypeParams))); - actualTypeParams = new List(); - - if (formalIns.Count != actualIns.Count) { - tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1}", - opName, actualIns.Count); - // if there are no type parameters, we can still return the result - // type and hope that the type checking proceeds - return typeParams.Count == 0 ? formalOuts : null; - } else if (actualOuts != null && formalOuts.Count != actualOuts.Count) { - tc.Error(typeCheckingSubject, "wrong number of result variables in {0}: {1}", - opName, actualOuts.Count); - // if there are no type parameters, we can still return the result - // type and hope that the type checking proceeds - actualTypeParams = new List(); - return typeParams.Count == 0 ? formalOuts : null; - } - - int previousErrorCount = tc.ErrorCount; - IDictionary subst = - MatchArgumentTypes(typeParams, formalIns, actualIns, - actualOuts != null ? formalOuts : null, actualOuts, opName, tc); - Contract.Assert(cce.NonNullDictionaryAndValues(subst)); - foreach (TypeVariable/*!*/ var in typeParams) { - Contract.Assert(var != null); - actualTypeParams.Add(subst[var]); - } - - List/*!*/ actualResults = new List(); - foreach (Type/*!*/ t in formalOuts) { - Contract.Assert(t != null); - actualResults.Add(t.Substitute(subst)); - } - List resultFreeVars = FreeVariablesIn(actualResults); - if (previousErrorCount != tc.ErrorCount) { - // errors occured when matching the formal arguments - // in case we have been able to substitute all type parameters, - // we can still return the result type and hope that the - // type checking proceeds in a meaningful manner - if (typeParams.All(param => !resultFreeVars.Contains(param))) - return actualResults; - else - // otherwise there is no point in returning the result type, - // type checking would only get confused even further - return null; - } - - Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !resultFreeVars.Contains(typeParams[index]))); - return actualResults; - } - - /////////////////////////////////////////////////////////////////////////// - - // about the same as Type.CheckArgumentTypes, but without - // detailed error reports - public static Type/*!*/ InferValueType(List/*!*/ typeParams, - List/*!*/ formalArgs, - Type/*!*/ formalResult, - List/*!*/ actualArgs) { - Contract.Requires(typeParams != null); - Contract.Requires(formalArgs != null); - Contract.Requires(formalResult != null); - Contract.Requires(actualArgs != null); - Contract.Ensures(Contract.Result() != null); - - IDictionary/*!*/ subst = - InferTypeParameters(typeParams, formalArgs, actualArgs); - Contract.Assert(cce.NonNullDictionaryAndValues(subst)); - - Type/*!*/ res = formalResult.Substitute(subst); - Contract.Assert(res != null); - // all type parameters have to be substituted with concrete types - List/*!*/ resFreeVars = res.FreeVariables; - Contract.Assert(resFreeVars != null); - Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !resFreeVars.Contains(typeParams[var]))); - return res; - } - -#if OLD_UNIFICATION - public static IDictionary! - InferTypeParameters(List! typeParams, - List! formalArgs, - List! actualArgs) - { - Contract.Requires(formalArgs.Length == actualArgs.Length); - - List! boundVarSeq0 = new List (); - List! boundVarSeq1 = new List (); - Dictionary! subst = new Dictionary(); - - for (int i = 0; i < formalArgs.Length; ++i) { - try { - Contract.Assert(forall{TypeVariable! var in typeParams); - !actualArgs[i].FreeVariables.Has(var)}; - formalArgs[i].Unify(actualArgs[i], typeParams, - boundVarSeq0, boundVarSeq1, subst); - } catch (UnificationFailedException) { - System.Diagnostics.Debug.Fail("Type unification failed: " + - formalArgs[i] + " vs " + actualArgs[i]); - } - } - - // we only allow type parameters to be substituted - Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); - return subst; - } -#else - /// - /// like Type.CheckArgumentTypes, but assumes no errors - /// (and only does arguments, not results; and takes actuals as List, not List) - /// - public static IDictionary/*!*/ - InferTypeParameters(List/*!*/ typeParams, - List/*!*/ formalArgs, - List/*!*/ actualArgs) { - Contract.Requires(typeParams != null); - Contract.Requires(formalArgs != null); - Contract.Requires(actualArgs != null);Contract.Requires(formalArgs.Count == actualArgs.Count); - Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); - - - List proxies = new List(); - Dictionary/*!*/ subst = new Dictionary(); - foreach (TypeVariable/*!*/ tv in typeParams) { - Contract.Assert(tv != null); - TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); - proxies.Add(proxy); - subst.Add(tv, proxy); - } - - for (int i = 0; i < formalArgs.Count; i++) { - Type formal = formalArgs[i].Substitute(subst); - Type actual = actualArgs[i]; - // if the type variables to be matched occur in the actual - // argument types, something has gone very wrong - Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); - - if (!formal.Unify(actual)) { - Contract.Assume(false); // caller expected no errors - } - } - - return subst; - } -#endif - - //----------- Helper methods to deal with bound type variables --------------- - - public static void EmitOptionalTypeParams(TokenTextWriter stream, List typeParams) { - Contract.Requires(typeParams != null); - Contract.Requires(stream != null); - if (typeParams.Count > 0) { - stream.Write("<"); - typeParams.Emit(stream, ","); // default binding strength of 0 is ok - stream.Write(">"); - } - } - - // Sort the type parameters according to the order of occurrence in the argument types - public static List/*!*/ SortTypeParams(List/*!*/ typeParams, List/*!*/ argumentTypes, Type resultType) { - Contract.Requires(typeParams != null); - Contract.Requires(argumentTypes != null); - Contract.Ensures(Contract.Result>() != null); - - Contract.Ensures(Contract.Result>().Count == typeParams.Count); - if (typeParams.Count == 0) { - return typeParams; - } - - List freeVarsInUse = FreeVariablesIn(argumentTypes); - if (resultType != null) { - freeVarsInUse.AppendWithoutDups(resultType.FreeVariables); - } - // "freeVarsInUse" is already sorted, but it may contain type variables not in "typeParams". - // So, project "freeVarsInUse" onto "typeParams": - List sortedTypeParams = new List(); - foreach (TypeVariable/*!*/ var in freeVarsInUse) { - Contract.Assert(var != null); - if (typeParams.Contains(var)) { - sortedTypeParams.Add(var); - } - } - - if (sortedTypeParams.Count < typeParams.Count) - // add the type parameters not mentioned in "argumentTypes" in - // the end of the list (this can happen for quantifiers) - sortedTypeParams.AppendWithoutDups(typeParams); - - return sortedTypeParams; - } - - // Check that each of the type parameters occurs in at least one argument type. - // Return true if some type parameters appear only among "moreArgumentTypes" and - // not in "argumentTypes". - [Pure] - public static bool CheckBoundVariableOccurrences(List/*!*/ typeParams, - List/*!*/ argumentTypes, - List moreArgumentTypes, - IToken/*!*/ resolutionSubject, - string/*!*/ subjectName, - ResolutionContext/*!*/ rc) { - Contract.Requires(typeParams != null); - Contract.Requires(argumentTypes != null); - Contract.Requires(resolutionSubject != null); - Contract.Requires(subjectName != null); - Contract.Requires(rc != null); - List freeVarsInArgs = FreeVariablesIn(argumentTypes); - List moFreeVarsInArgs = moreArgumentTypes == null ? null : FreeVariablesIn(moreArgumentTypes); - bool someTypeParamsAppearOnlyAmongMo = false; - foreach (TypeVariable/*!*/ var in typeParams) { - Contract.Assert(var != null); - if (rc.LookUpTypeBinder(var.Name) == var) // avoid to complain twice about variables that are bound multiple times - { - if (freeVarsInArgs.Contains(var)) { - // cool - } else if (moFreeVarsInArgs != null && moFreeVarsInArgs.Contains(var)) { - someTypeParamsAppearOnlyAmongMo = true; - } else { - rc.Error(resolutionSubject, - "type variable must occur in {0}: {1}", - subjectName, var); - } - } - } - return someTypeParamsAppearOnlyAmongMo; - } - - [Pure] - public static List FreeVariablesIn(List arguments) { - Contract.Requires(arguments != null); - Contract.Ensures(Contract.Result>() != null); - List/*!*/ res = new List(); - foreach (Type/*!*/ t in arguments) { - Contract.Assert(t != null); - res.AppendWithoutDups(t.FreeVariables); - } - return res; - } - } - [ContractClassFor(typeof(Type))] - public abstract class TypeContracts : Type { - public TypeContracts() :base(null){ - - } - public override List FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - throw new NotImplementedException(); - } - } - public override List FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - throw new NotImplementedException(); - } - } - public override Type Clone(IDictionary varMap) { - Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - Contract.Requires(stream != null); - throw new NotImplementedException(); - } - public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { - Contract.Requires(that != null); - Contract.Requires(thisBoundVariables != null); - Contract.Requires(thatBoundVariables != null); - throw new NotImplementedException(); - } - public override bool Unify(Type that, List unifiableVariables, IDictionary unifier) { - Contract.Requires(that != null); - Contract.Requires(unifiableVariables != null); - Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); - Contract.Requires(Contract.ForAll(unifier.Keys, key => unifiableVariables.Contains(key))); - Contract.Requires(IsIdempotent(unifier)); - throw new NotImplementedException(); - } - public override Type Substitute(IDictionary subst) { - Contract.Requires(cce.NonNullDictionaryAndValues(subst)); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override Type ResolveType(ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - public override int GetHashCode(List boundVariables) { - Contract.Requires(boundVariables != null); - throw new NotImplementedException(); - } - } - //===================================================================== - - public class BasicType : Type { - public readonly SimpleType T; - public BasicType(IToken/*!*/ token, SimpleType t) - : base(token) { - Contract.Requires(token != null); - T = t; - } - public BasicType(SimpleType t) - : base(Token.NoToken) { - T = t; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // BasicTypes are immutable anyway, we do not clone - return this; - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - // no parentheses are necessary for basic types - stream.SetToken(this); - stream.Write("{0}", this); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - switch (T) { - case SimpleType.Int: - return "int"; - case SimpleType.Real: - return "real"; - case SimpleType.Bool: - return "bool"; - } - Debug.Assert(false, "bad type " + T); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // make compiler happy - } - - //----------- Equality ---------------------------------- - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - // shortcut - Type thatType = that as Type; - if (thatType == null) - return false; - BasicType thatBasicType = TypeProxy.FollowProxy(thatType.Expanded) as BasicType; - return thatBasicType != null && this.T == thatBasicType.T; - } - - [Pure] - public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(that != null); - return this.Equals(that); - } - - //----------- Unification of types ----------- - - public override bool Unify(Type that, List unifiableVariables, IDictionary/*!*/ unifier) { - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(that != null); - //Contract.Requires(cce.NonNullElements(unifier)); - // an idempotent substitution that describes the - // unification result up to a certain point - - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) { - return that.Unify(this, unifiableVariables, unifier); - } else { - return this.Equals(that); - } - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - } else { - if (!this.Equals(that)) - throw UNIFICATION_FAILED; - } - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - return this.T.GetHashCode(); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - // determine the free variables in a type, in the order in which the variables occur - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return new List(); // basic type are closed - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBasic { - get { - return true; - } - } - public override bool IsInt { - get { - return this.T == SimpleType.Int; - } - } - public override bool IsReal { - get { - return this.T == SimpleType.Real; - } - } - public override bool IsBool { - get { - return this.T == SimpleType.Bool; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBasicType(this); - } - } - - //===================================================================== - - public class BvType : Type { - public readonly int Bits; - - public BvType(IToken token, int bits) - : base(token) { - Contract.Requires(token != null); - Bits = bits; - } - - public BvType(int bits) - : base(Token.NoToken) { - Bits = bits; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively. - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // BvTypes are immutable anyway, we do not clone - return this; - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - // no parentheses are necessary for bitvector-types - stream.SetToken(this); - stream.Write("{0}", this); - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - return "bv" + Bits; - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - BvType thatBvType = TypeProxy.FollowProxy(that.Expanded) as BvType; - return thatBvType != null && this.Bits == thatBvType.Bits; - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(unifier)); - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) { - return that.Unify(this, unifiableVariables, unifier); - } else { - return this.Equals(that); - } - } - -#if OLD_UNIFICATION - public override void Unify(Type that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary result){ -Contract.Requires(result != null); -Contract.Requires(that != null); - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - } else { - if (!this.Equals(that)) - throw UNIFICATION_FAILED; - } - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - return this.Bits.GetHashCode(); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - // determine the free variables in a type, in the order in which the variables occur - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return new List(); // bitvector-type are closed - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBv { - get { - return true; - } - } - public override int BvBits { - get { - return Bits; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvType(this); - } - } - - //===================================================================== - - // An AST node containing an identifier and a sequence of type arguments, which - // will be turned either into a TypeVariable, into a CtorType or into a BvType - // during the resolution phase - public class UnresolvedTypeIdentifier : Type { - public readonly string/*!*/ Name; - public readonly List/*!*/ Arguments; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - Contract.Invariant(Arguments != null); - } - - - public UnresolvedTypeIdentifier(IToken token, string name) - : this(token, name, new List()) { - Contract.Requires(name != null); - Contract.Requires(token != null); - } - - public UnresolvedTypeIdentifier(IToken token, string name, List arguments) - : base(token) { - Contract.Requires(arguments != null); - Contract.Requires(name != null); - Contract.Requires(token != null); - this.Name = name; - this.Arguments = arguments; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(varMap)); - } - return new UnresolvedTypeIdentifier(tok, Name, newArgs); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - return new UnresolvedTypeIdentifier(tok, Name, newArgs); - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Equals should never be called"); - return false; // to make the compiler happy - } - - //----------- Unification of types ----------- - - public override bool Unify(Type that, - List/*!*/ unifiableVariables, - IDictionary result) { - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(result)); - //Contract.Requires(that != null); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // UnresolvedTypeIdentifier.Unify should never be called - } - -#if OLD_UNIFICATION - public override void Unify(Type that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary result){ -Contract.Requires(result != null); -Contract.Requires(that != null); - System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Unify should never be called"); - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // UnresolvedTypeIdentifier.Substitute should never be called - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // UnresolvedTypeIdentifier.GetHashCode should never be called - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - // first case: the type name denotes a bitvector-type - if (Name.StartsWith("bv") && Name.Length > 2) { - bool is_bv = true; - for (int i = 2; i < Name.Length; ++i) { - if (!char.IsDigit(Name[i])) { - is_bv = false; - break; - } - } - if (is_bv) { - if (Arguments.Count > 0) { - rc.Error(this, - "bitvector types must not be applied to arguments: {0}", - Name); - } - return new BvType(tok, int.Parse(Name.Substring(2))); - } - } - - // second case: the identifier is resolved to a type variable - TypeVariable var = rc.LookUpTypeBinder(Name); - if (var != null) { - if (Arguments.Count > 0) { - rc.Error(this, - "type variables must not be applied to arguments: {0}", - var); - } - return var; - } - - // third case: the identifier denotes a type constructor and we - // recursively resolve the arguments - TypeCtorDecl ctorDecl = rc.LookUpType(Name); - if (ctorDecl != null) { - if (Arguments.Count != ctorDecl.Arity) { - rc.Error(this, - "type constructor received wrong number of arguments: {0}", - ctorDecl); - return this; - } - return new CtorType(tok, ctorDecl, ResolveArguments(rc)); - } - - // fourth case: the identifier denotes a type synonym - TypeSynonymDecl synDecl = rc.LookUpTypeSynonym(Name); - if (synDecl != null) { - if (Arguments.Count != synDecl.TypeParameters.Count) { - rc.Error(this, - "type synonym received wrong number of arguments: {0}", - synDecl); - return this; - } - List/*!*/ resolvedArgs = ResolveArguments(rc); - Contract.Assert(resolvedArgs != null); - - return new TypeSynonymAnnotation(this.tok, synDecl, resolvedArgs); - - } - - // otherwise: this name is not declared anywhere - rc.Error(this, "undeclared type: {0}", Name); - return this; - } - - private List ResolveArguments(ResolutionContext rc) { - Contract.Requires(rc != null); - Contract.Ensures(Contract.Result>() != null); - List/*!*/ resolvedArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - resolvedArgs.Add(t.ResolveType(rc)); - } - return resolvedArgs; - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return new List(); - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - // PR: should unresolved types be syntactically distinguished from resolved types? - CtorType.EmitCtorType(this.Name, Arguments, stream, contextBindingStrength); - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsUnresolved { - get { - return true; - } - } - public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - return this; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitUnresolvedTypeIdentifier(this); - } - } - - //===================================================================== - - public class TypeVariable : Type { - public readonly string/*!*/ Name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - } - - - public TypeVariable(IToken token, string name) - : base(token) { - Contract.Requires(name != null); - Contract.Requires(token != null); - this.Name = name; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - // if this variable is mapped to some new variable, we take the new one - // otherwise, return this - TypeVariable res; - varMap.TryGetValue(this, out res); - if (res == null) - return this; - else - return res; - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return this; - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - TypeVariable thatAsTypeVar = TypeProxy.FollowProxy(that.Expanded) as TypeVariable; - - if (thatAsTypeVar == null) - return false; - - int thisIndex = thisBoundVariables.LastIndexOf(this); - int thatIndex = thatBoundVariables.LastIndexOf(thatAsTypeVar); - return (thisIndex >= 0 && thisIndex == thatIndex) || - (thisIndex == -1 && thatIndex == -1 && - Object.ReferenceEquals(this, thatAsTypeVar)); - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - // an idempotent substitution that describes the - // unification result up to a certain point - IDictionary/*!*/ unifier) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(unifier)); - that = that.Expanded; - if (that is TypeProxy && !(that is ConstrainedProxy)) - return that.Unify(this, unifiableVariables, unifier); - - if (this.Equals(that)) - return true; - - if (unifiableVariables.Contains(this)) { - Type previousSubst; - unifier.TryGetValue(this, out previousSubst); - if (previousSubst == null) { - return addSubstitution(unifier, that); - } else { - // we have to unify the old instantiation with the new one - return previousSubst.Unify(that, unifiableVariables, unifier); - } - } - - // this cannot be instantiated with anything - // but that possibly can ... - - TypeVariable tv = that as TypeVariable; - - return tv != null && - unifiableVariables.Contains(tv) && - that.Unify(this, unifiableVariables, unifier); - } - - // TODO: the following might cause problems, because when applying substitutions - // to type proxies the substitutions are not propagated to the proxy - // constraints (right now at least) - private bool addSubstitution(IDictionary/*!*/ oldSolution, - // the type that "this" is instantiated with - Type/*!*/ newSubst) { - Contract.Requires(cce.NonNullDictionaryAndValues(oldSolution)); - Contract.Requires(newSubst != null); - Contract.Requires(!oldSolution.ContainsKey(this)); - - Dictionary/*!*/ newMapping = new Dictionary(); - // apply the old (idempotent) substitution to the new instantiation - Type/*!*/ substSubst = newSubst.Substitute(oldSolution); - Contract.Assert(substSubst != null); - // occurs check - if (substSubst.FreeVariables.Contains(this)) - return false; - newMapping.Add(this, substSubst); - - // apply the new substitution to the old ones to ensure idempotence - List/*!*/ keys = new List(); - keys.AddRange(oldSolution.Keys); - foreach (TypeVariable/*!*/ var in keys) { - Contract.Assert(var != null); - oldSolution[var] = oldSolution[var].Substitute(newMapping); - } - oldSolution.Add(this, substSubst); - - Contract.Assert(IsIdempotent(oldSolution)); - return true; - } - -#if OLD_UNIFICATION - public override void Unify(Type that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary result){ -Contract.Requires(result != null); -Contract.Requires(that != null); - that = that.Expanded; - int thisIndex = thisBoundVariables.LastIndexOf(this); - if (thisIndex == -1) { - // this is not a bound variable and can possibly be matched on that - // that must not contain any bound variables - List! thatFreeVars = that.FreeVariables; - if (thatBoundVariables.Any(var=> thatFreeVars.Has(var))) - throw UNIFICATION_FAILED; - - // otherwise, in case that is a typevariable it cannot be bound and - // we can just check for equality - if (this.Equals(that)) - return; - - if (!unifiableVariables.Has(this)) { - // this cannot be instantiated with anything - // but that possibly can ... - if ((that is TypeVariable) && - unifiableVariables.Has(that as TypeVariable)) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - return; - } else { - throw UNIFICATION_FAILED; - } - } - - Type previousSubst; - result.TryGetValue(this, out previousSubst); - if (previousSubst == null) { - addSubstitution(result, that); - } else { - // we have to unify the old instantiation with the new one - previousSubst.Unify(that, unifiableVariables, thisBoundVariables, thatBoundVariables, result); - } - } else { - // this is a bound variable, that also has to be one (with the same index) - if (!(that is TypeVariable) || - thatBoundVariables.LastIndexOf(that) != thisIndex) - throw UNIFICATION_FAILED; - } - } - -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - Type res; - if (subst.TryGetValue(this, out res)) { - Contract.Assert(res != null); - return res; - } else { - return this; - } - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - int thisIndex = boundVariables.LastIndexOf(this); - if (thisIndex == -1) - return GetBaseHashCode(); - return thisIndex * 27473671; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - // never put parentheses around variables - stream.SetToken(this); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - //Contract.Ensures(Contract.Result() != null); - // nothing to resolve - return this; - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - return new List { this }; - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return new List(); - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsVariable { - get { - return true; - } - } - public override TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - return this; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - //Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeVariable(this); - } - } - - //===================================================================== - - public class TypeProxy : Type { - static int proxies = 0; - protected readonly string/*!*/ Name; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Name != null); - } - - - public TypeProxy(IToken token, string givenName) - : this(token, givenName, "proxy") { - Contract.Requires(givenName != null); - Contract.Requires(token != null); - } - - protected TypeProxy(IToken token, string givenName, string kind) - : base(token) { - Contract.Requires(kind != null); - Contract.Requires(givenName != null); - Contract.Requires(token != null); - Name = givenName + "$" + kind + "#" + proxies; - proxies++; - } - - private Type proxyFor; - public Type ProxyFor { - // apply path shortening, and then return the value of proxyFor - get { - TypeProxy anotherProxy = proxyFor as TypeProxy; - if (anotherProxy != null && anotherProxy.proxyFor != null) { - // apply path shortening by bypassing "anotherProxy" (and possibly others) - proxyFor = anotherProxy.ProxyFor; - Contract.Assert(proxyFor != null); - } - return proxyFor; - } - } - - [Pure] - [Reads(ReadsAttribute.Reads.Everything)] - public static Type FollowProxy(Type t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(!(Contract.Result() is TypeProxy) || ((TypeProxy)Contract.Result()).proxyFor == null); - if (t is TypeProxy) { - Type p = ((TypeProxy)t).ProxyFor; - if (p != null) { - return p; - } - } - return t; - } - - protected void DefineProxy(Type ty) { - Contract.Requires(ty != null); - Contract.Requires(ProxyFor == null); - // follow ty down to the leaf level, so that we can avoid creating a cycle - ty = FollowProxy(ty); - if (!object.ReferenceEquals(this, ty)) { - proxyFor = ty; - } - } - - //----------- Cloning ---------------------------------- - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Clone(varMap); - } else { - return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy - } - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - //Contract.Requires(that != null); - if (object.ReferenceEquals(this, that)) { - return true; - } - Type p = ProxyFor; - if (p != null) { - return p.Equals(that, thisBoundVariables, thatBoundVariables); - } else { - // This proxy could be made to be equal to anything, so what to return? - return false; - } - } - - //----------- Unification of types ----------- - - // determine whether the occurs check fails: this is a strict subtype of that - protected bool ReallyOccursIn(Type that) { - Contract.Requires(that != null); - that = FollowProxy(that.Expanded); - return that.FreeProxies.Contains(this) && - (that.IsCtor || that.IsMap && this != that && this.ProxyFor != that); - } - - public override bool Unify(Type that, - List/*!*/ unifiableVariables, - IDictionary result) { - //Contract.Requires(cce.NonNullElements(result)); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(that != null); - Type p = ProxyFor; - if (p != null) { - return p.Unify(that, unifiableVariables, result); - } else { - // unify this with that - if (this.ReallyOccursIn(that)) - return false; - DefineProxy(that.Expanded); - return true; - } - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Substitute(subst); - } else { - return this; - } - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - Type p = ProxyFor; - if (p != null) { - return p.GetHashCode(boundVariables); - } else { - return GetBaseHashCode(); - } - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - Type p = ProxyFor; - if (p != null) { - p.Emit(stream, contextBindingStrength); - } else { - // no need for parentheses - stream.SetToken(this); - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); - } - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.ResolveType(rc); - } else { - return this; - } - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - Type p = ProxyFor; - if (p != null) { - return p.FreeVariables; - } else { - return new List(); - } - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Type p = ProxyFor; - if (p != null) { - return p.FreeProxies; - } else { - List/*!*/ res = new List(); - res.Add(this); - return res; - } - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBasic { - get { - Type p = ProxyFor; - return p != null && p.IsBasic; - } - } - public override bool IsInt { - get { - Type p = ProxyFor; - return p != null && p.IsInt; - } - } - public override bool IsReal { - get { - Type p = ProxyFor; - return p != null && p.IsReal; - } - } - public override bool IsBool { - get { - Type p = ProxyFor; - return p != null && p.IsBool; - } - } - - public override bool IsVariable { - get { - Type p = ProxyFor; - return p != null && p.IsVariable; - } - } - public override TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsVariable; - } - } - - public override bool IsCtor { - get { - Type p = ProxyFor; - return p != null && p.IsCtor; - } - } - public override CtorType/*!*/ AsCtor { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsCtor; - } - } - public override bool IsMap { - get { - Type p = ProxyFor; - return p != null && p.IsMap; - } - } - public override MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsMap; - } - } - public override int MapArity { - get { - Type p = ProxyFor; - Contract.Assume(p != null); - return p.MapArity; - } - } - public override bool IsUnresolved { - get { - Type p = ProxyFor; - return p != null && p.IsUnresolved; - } - } - public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - Contract.Assume(p != null); - return p.AsUnresolved; - } - } - - public override bool IsBv { - get { - Type p = ProxyFor; - return p != null && p.IsBv; - } - } - public override int BvBits { - get { - Type p = ProxyFor; - Contract.Assume(p != null); - return p.BvBits; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeProxy(this); - } - } - - public abstract class ConstrainedProxy : TypeProxy { - protected ConstrainedProxy(IToken token, string givenName, string kind) - : base(token, givenName, kind) { - Contract.Requires(kind != null); - Contract.Requires(givenName != null); - Contract.Requires(token != null); - } - } - - /// - /// Each instance of this class represents a set of bitvector types. In particular, it represents - /// a bitvector type bvN iff - /// minBits ATMOST N and - /// foreach constraint (t0,t1), the types represented by t0 and t1 are bitvector types whose - /// number of bits add up to N. - /// This means that the size of a BvTypeProxy p is constrained not only by p.minBits, but also - /// by the size of various t0 and t1 types that are transitively part of BvTypeProxy constraints. - /// If such a t0 or t1 were to get its ProxyFor field defined, then p would have to be further - /// constrained too. This doesn't seem like it would ever occur in a Boogie 2 program, because: - /// the only place where a BvTypeProxy with constraints can occur is as the type of a - /// BvConcatExpr, and - /// the types of all local variables are explicitly declared, which means that the types of - /// subexpressions of a BvConcatExpr are not going to change other than via the type of the - /// BvConcatExpr. - /// So, this implementation of BvTypeProxy does not keep track of where a BvTypeProxy may occur - /// transitively in some other BvTypeProxy's constraints. - /// - public class BvTypeProxy : ConstrainedProxy { - public int MinBits; - List constraints; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullElements(constraints, true)); - } - - class BvTypeConstraint { - public Type/*!*/ T0; - public Type/*!*/ T1; - public BvTypeConstraint(Type t0, Type t1) { - Contract.Requires(t1 != null); - Contract.Requires(t0 != null); - Contract.Requires(t0.IsBv && t1.IsBv); - T0 = t0; - T1 = t1; - } - } - - public BvTypeProxy(IToken token, string name, int minBits) - : base(token, name, "bv" + minBits + "proxy") { - Contract.Requires(name != null); - Contract.Requires(token != null); - this.MinBits = minBits; - } - - /// - /// Requires that any further constraints to be placed on t0 and t1 go via the object to - /// be constructed. - /// - public BvTypeProxy(IToken token, string name, Type t0, Type t1) - : base(token, name, "bvproxy") { - Contract.Requires(t1 != null); - Contract.Requires(t0 != null); - Contract.Requires(name != null); - Contract.Requires(token != null); - Contract.Requires(t0.IsBv && t1.IsBv); - t0 = FollowProxy(t0); - t1 = FollowProxy(t1); - this.MinBits = MinBitsFor(t0) + MinBitsFor(t1); - List list = new List(); - list.Add(new BvTypeConstraint(t0, t1)); - this.constraints = list; - } - - /// - /// Construct a BvTypeProxy like p, but with minBits. - /// - private BvTypeProxy(BvTypeProxy p, int minBits) - : base(p.tok, p.Name, "") { - Contract.Requires(p != null); - this.MinBits = minBits; - this.constraints = p.constraints; - } - - private BvTypeProxy(IToken token, string name, int minBits, List constraints) - : base(token, name, "") { - Contract.Requires(cce.NonNullElements(constraints, true)); - Contract.Requires(name != null); - Contract.Requires(token != null); - this.MinBits = minBits; - this.constraints = constraints; - } - - [Pure] - [Reads(ReadsAttribute.Reads.Everything)] - private static int MinBitsFor(Type t) { - Contract.Requires(t != null); - Contract.Requires(t.IsBv); - Contract.Ensures(0 <= Contract.Result()); - - if (t is TypeSynonymAnnotation) { - return MinBitsFor(((TypeSynonymAnnotation)t).ExpandedType); - } - - if (t is BvType) { - return t.BvBits; - } else { - return ((BvTypeProxy)t).MinBits; - } - } - - //----------- Cloning ---------------------------------- - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Clone(varMap); - } else { - return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy - } - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy - } - - //----------- Unification of types ----------- - - public override bool Unify(Type that, - List unifiableVariables, - IDictionary result) { - //Contract.Requires(cce.NonNullElements(result)); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(that != null); - Type p = ProxyFor; - if (p != null) { - return p.Unify(that, unifiableVariables, result); - } - - // unify this with that, if possible - that = that.Expanded; - that = FollowProxy(that); - - if (this.ReallyOccursIn(that)) - return false; - - TypeVariable tv = that as TypeVariable; - - if (tv != null && unifiableVariables.Contains(tv)) - return that.Unify(this, unifiableVariables, result); - - if (object.ReferenceEquals(this, that)) { - return true; - } else if (that is BvType) { - if (MinBits <= that.BvBits) { - if (constraints != null) { - foreach (BvTypeConstraint btc in constraints) { - int minT1 = MinBitsFor(btc.T1); - int left = IncreaseBits(btc.T0, that.BvBits - minT1); - left = IncreaseBits(btc.T1, minT1 + left); - Contract.Assert(left == 0); // because it should always be possible to increase the total size of a BvTypeConstraint pair (t0,t1) arbitrarily - } - } - DefineProxy(that); - return true; - } - } else if (that is BvTypeProxy) { - BvTypeProxy bt = (BvTypeProxy)that; - // keep the proxy with the stronger constraint (that is, the higher minBits), but if either - // has a constraints list, then concatenate both constraints lists and define the previous - // proxies to the new one - if (this.constraints != null || bt.constraints != null) { - List list = new List(); - if (this.constraints != null) { - list.AddRange(this.constraints); - } - if (bt.constraints != null) { - list.AddRange(bt.constraints); - } - BvTypeProxy np = new BvTypeProxy(this.tok, this.Name, Math.Max(this.MinBits, bt.MinBits), list); - this.DefineProxy(np); - bt.DefineProxy(np); - } else if (this.MinBits <= bt.MinBits) { - this.DefineProxy(bt); - } else { - bt.DefineProxy(this); - } - return true; - } else if (that is ConstrainedProxy) { - // only bitvector proxies can be unified with this BvTypeProxy - return false; - } else if (that is TypeProxy) { - // define: that.ProxyFor := this; - return that.Unify(this, unifiableVariables, result); - } - return false; - } - - private static int IncreaseBits(Type t, int to) { - Contract.Requires(t != null); - Contract.Requires(t.IsBv && 0 <= to && MinBitsFor(t) <= to); - Contract.Ensures(0 <= Contract.Result() && Contract.Result() <= to); - - if(t is TypeSynonymAnnotation) { - return IncreaseBits(((TypeSynonymAnnotation)t).ExpandedType, to); - } - - t = FollowProxy(t); - if (t is BvType) { - return to - t.BvBits; - } else { - BvTypeProxy p = (BvTypeProxy)t; - Contract.Assert(p.MinBits <= to); - if (p.MinBits < to) { - BvTypeProxy q = new BvTypeProxy(p, to); - p.DefineProxy(q); - } - return 0; // we were able to satisfy the request completely - } - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (this.ProxyFor == null) { - // check that the constraints are clean and do not contain any - // of the substituted variables (otherwise, we are in big trouble) - Contract.Assert(Contract.ForAll(constraints, c => - Contract.ForAll(subst.Keys, var => - !c.T0.FreeVariables.Contains(var) && !c.T1.FreeVariables.Contains(var)))); - } - return base.Substitute(subst); - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBv { - get { - return true; - } - } - public override int BvBits { - get { - // This method is supposed to return the number of bits supplied, but unless the proxy has been resolved, - // we only have a lower bound on the number of bits supplied. But this method is not supposed to be - // called until type checking has finished, at which time the minBits is stable. - Type p = ProxyFor; - if (p != null) { - return p.BvBits; - } else { - return MinBits; - } - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitBvTypeProxy(this); - } - } - - // Proxy representing map types with a certain arity. Apart from the arity, - // a number of constraints on the index and value type of the map type may - // be known (such constraints result from applied select and store operations). - // Because map type can be polymorphic (in the most general case, each index or - // value type is described by a separate type parameter) any combination of - // constraints can be satisfied. - public class MapTypeProxy : ConstrainedProxy { - public readonly int Arity; - private readonly List/*!*/ constraints = new List(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(constraints != null); - } - - - // each constraint specifies that the given combination of argument/result - // types must be a possible instance of the formal map argument/result types - private struct Constraint { - public readonly List/*!*/ Arguments; - public readonly Type/*!*/ Result; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Arguments != null); - Contract.Invariant(Result != null); - } - - - public Constraint(List arguments, Type result) { - Contract.Requires(result != null); - Contract.Requires(arguments != null); - Arguments = arguments; - Result = result; - } - - public Constraint Clone(IDictionary/*!*/ varMap) { - Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); - List/*!*/ args = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - args.Add(t.Clone(varMap)); - } - Type/*!*/ res = Result.Clone(varMap); - Contract.Assert(res != null); - return new Constraint(args, res); - } - - public bool Unify(MapType that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - Contract.Requires(unifiableVariables != null); - Contract.Requires(cce.NonNullDictionaryAndValues(result)); - Contract.Requires(that != null); - Contract.Requires(Arguments.Count == that.Arguments.Count); - Dictionary/*!*/ subst = new Dictionary(); - foreach (TypeVariable/*!*/ tv in that.TypeParameters) { - Contract.Assert(tv != null); - TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); - subst.Add(tv, proxy); - } - - bool good = true; - for (int i = 0; i < that.Arguments.Count; i++) { - Type t0 = that.Arguments[i].Substitute(subst); - Type t1 = this.Arguments[i]; - good &= t0.Unify(t1, unifiableVariables, result); - } - good &= that.Result.Substitute(subst).Unify(this.Result, unifiableVariables, result); - return good; - } - } - - public MapTypeProxy(IToken token, string name, int arity) - : base(token, name, "mapproxy") { - Contract.Requires(name != null); - Contract.Requires(token != null); - Contract.Requires(0 <= arity); - this.Arity = arity; - } - - private void AddConstraint(Constraint c) { - Contract.Requires(c.Arguments.Count == Arity); - - Type f = ProxyFor; - MapType mf = f as MapType; - if (mf != null) { - bool success = c.Unify(mf, new List(), new Dictionary()); - Contract.Assert(success); - return; - } - - MapTypeProxy mpf = f as MapTypeProxy; - if (mpf != null) { - mpf.AddConstraint(c); - return; - } - - Contract.Assert(f == null); // no other types should occur as specialisations of this proxy - - constraints.Add(c); - } - - public Type CheckArgumentTypes(List/*!*/ actualArgs, - out TypeParamInstantiation/*!*/ tpInstantiation, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) { - Contract.Requires(actualArgs != null); - Contract.Requires(typeCheckingSubject != null); - Contract.Requires(opName != null); - Contract.Requires(tc != null); - Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - - - - Type f = ProxyFor; - MapType mf = f as MapType; - if (mf != null) - return mf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); - - MapTypeProxy mpf = f as MapTypeProxy; - if (mpf != null) - return mpf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); - - Contract.Assert(f == null); // no other types should occur as specialisations of this proxy - - // otherwise, we just record the constraints given by this usage of the map type - List/*!*/ arguments = new List(); - foreach (Expr/*!*/ e in actualArgs) { - Contract.Assert(e != null); - arguments.Add(e.Type); - } - Type/*!*/ result = new TypeProxy(tok, "result"); - Contract.Assert(result != null); - AddConstraint(new Constraint(arguments, result)); - - List/*!*/ argumentsResult = new List(); - foreach (Expr/*!*/ e in actualArgs) { - Contract.Assert(e != null); - argumentsResult.Add(e.Type); - } - argumentsResult.Add(result); - - tpInstantiation = new MapTypeProxyParamInstantiation(this, argumentsResult); - return result; - } - - //----------- Cloning ---------------------------------- - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - Type p = ProxyFor; - if (p != null) { - return p.Clone(varMap); - } else { - MapTypeProxy p2 = new MapTypeProxy(tok, Name, Arity); - foreach (Constraint c in constraints) - p2.AddConstraint(c.Clone(varMap)); - return p2; // the clone will have a name that ends with $mapproxy$mapproxy (hopefully) - } - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - Type p = ProxyFor; - if (p != null) { - p.Emit(stream, contextBindingStrength); - } else { - stream.Write("["); - string/*!*/ sep = ""; - for (int i = 0; i < Arity; ++i) { - stream.Write(sep); - sep = ", "; - stream.Write("?"); - } - stream.Write("]?"); - } - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(result)); - Type p = ProxyFor; - if (p != null) { - return p.Unify(that, unifiableVariables, result); - } - - // unify this with that, if possible - that = that.Expanded; - that = FollowProxy(that); - - if (this.ReallyOccursIn(that)) - return false; - - TypeVariable tv = that as TypeVariable; - - if (tv != null && unifiableVariables.Contains(tv)) - return that.Unify(this, unifiableVariables, result); - - if (object.ReferenceEquals(this, that)) { - return true; - } else if (that is MapType) { - MapType mapType = (MapType)that; - if (mapType.Arguments.Count == Arity) { - bool good = true; - foreach (Constraint c in constraints) - good &= c.Unify(mapType, unifiableVariables, result); - if (good) { - DefineProxy(mapType); - return true; - } - } - } else if (that is MapTypeProxy) { - MapTypeProxy mt = (MapTypeProxy)that; - if (mt.Arity == this.Arity) { - // we propagate the constraints of this proxy to the more specific one - foreach (Constraint c in constraints) - mt.AddConstraint(c); - DefineProxy(mt); - return true; - } - } else if (that is ConstrainedProxy) { - // only map-type proxies can be unified with this MapTypeProxy - return false; - } else if (that is TypeProxy) { - // define: that.ProxyFor := this; - return that.Unify(this, unifiableVariables, result); - } - return false; - } - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (this.ProxyFor == null) { - // check that the constraints are clean and do not contain any - // of the substituted variables (otherwise, we are in big trouble) - Contract.Assert(Contract.ForAll(constraints, c => - Contract.ForAll(subst.Keys, var => - Contract.ForAll(0, c.Arguments.Count, t => !c.Arguments[t].FreeVariables.Contains(var)) && - !c.Result.FreeVariables.Contains(var)))); - } - return base.Substitute(subst); - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsMap { - get { - return true; - } - } - public override MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - - Type p = ProxyFor; - if (p != null) { - return p.AsMap; - } else { - { - Contract.Assert(false); - throw new cce.UnreachableException(); - } // what to do now? - } - } - } - public override int MapArity { - get { - return Arity; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitMapTypeProxy(this); - } - } - - //===================================================================== - - // Used to annotate types with type synoyms that were used in the - // original unresolved types. Such types should be considered as - // equivalent to ExpandedType, the annotations are only used to enable - // better pretty-printing - public class TypeSynonymAnnotation : Type { - public Type/*!*/ ExpandedType; - - public readonly List/*!*/ Arguments; - // is set during resolution and determines whether the right number of arguments is given - public readonly TypeSynonymDecl/*!*/ Decl; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(ExpandedType != null); - Contract.Invariant(Arguments != null); - Contract.Invariant(Decl != null); - } - - - public TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(decl != null); - Contract.Requires(arguments != null); - Contract.Requires(arguments.Count == decl.TypeParameters.Count); - this.Decl = decl; - this.Arguments = arguments; - - // build a substitution that can be applied to the definition of - // the type synonym - IDictionary/*!*/ subst = - new Dictionary(); - for (int i = 0; i < arguments.Count; ++i) - subst.Add(decl.TypeParameters[i], arguments[i]); - - ExpandedType = decl.Body.Substitute(subst); - } - - private TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments, - Type/*!*/ expandedType) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(decl != null); - Contract.Requires(arguments != null); - Contract.Requires(expandedType != null); - - this.Decl = decl; - this.Arguments = arguments; - this.ExpandedType = expandedType; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(varMap)); - } - Type/*!*/ newExpandedType = ExpandedType.Clone(varMap); - Contract.Assert(newExpandedType != null); - return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - return new TypeSynonymAnnotation(tok, Decl, newArgs); - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - //Contract.Requires(that != null); - //Contract.Requires(thisBoundVariables != null); - //Contract.Requires(thatBoundVariables != null); - return ExpandedType.Equals(that, thisBoundVariables, thatBoundVariables); - } - - // used to skip leading type annotations - internal override Type/*!*/ Expanded { - get { - Contract.Ensures(Contract.Result() != null); - - return ExpandedType.Expanded; - } - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - //Contract.Requires(that != null); - //Contract.Requires(unifiableVariables != null); - //Contract.Requires(cce.NonNullElements(result)); - return ExpandedType.Unify(that, unifiableVariables, result); - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - ExpandedType.Unify(that, unifiableVariables, - thisBoundVariables, thatBoundVariables, result); - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (subst.Count == 0) - return this; - List newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Substitute(subst)); - } - Type/*!*/ newExpandedType = ExpandedType.Substitute(subst); - Contract.Assert(newExpandedType != null); - return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - return ExpandedType.GetHashCode(boundVariables); - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - CtorType.EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - List resolvedArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - resolvedArgs.Add(t.ResolveType(rc)); - } - return new TypeSynonymAnnotation(tok, Decl, resolvedArgs); - } - - public override List/*!*/ FreeVariables { - get { - Contract.Ensures(Contract.Result>() != null); - - return ExpandedType.FreeVariables; - } - } - - public override List/*!*/ FreeProxies { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return ExpandedType.FreeProxies; - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsBasic { - get { - return ExpandedType.IsBasic; - } - } - public override bool IsInt { - get { - return ExpandedType.IsInt; - } - } - public override bool IsReal { - get { - return ExpandedType.IsReal; - } - } - public override bool IsBool { - get { - return ExpandedType.IsBool; - } - } - - public override bool IsVariable { - get { - return ExpandedType.IsVariable; - } - } - public override TypeVariable/*!*/ AsVariable { - get { - Contract.Ensures(Contract.Result() != null); - return ExpandedType.AsVariable; - } - } - public override bool IsCtor { - get { - return ExpandedType.IsCtor; - } - } - public override CtorType/*!*/ AsCtor { - get { - Contract.Ensures(Contract.Result() != null); - return ExpandedType.AsCtor; - } - } - public override bool IsMap { - get { - return ExpandedType.IsMap; - } - } - public override MapType/*!*/ AsMap { - get { - Contract.Ensures(Contract.Result() != null); - return ExpandedType.AsMap; - } - } - public override bool IsUnresolved { - get { - return ExpandedType.IsUnresolved; - } - } - public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { - get { - Contract.Ensures(Contract.Result() != null); - - return ExpandedType.AsUnresolved; - } - } - - public override bool IsBv { - get { - return ExpandedType.IsBv; - } - } - public override int BvBits { - get { - return ExpandedType.BvBits; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitTypeSynonymAnnotation(this); - } - } - - //===================================================================== - - public class CtorType : Type { - public readonly List/*!*/ Arguments; - // is set during resolution and determines whether the right number of arguments is given - public readonly TypeCtorDecl/*!*/ Decl; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Arguments != null); - Contract.Invariant(Decl != null); - } - - - public CtorType(IToken/*!*/ token, TypeCtorDecl/*!*/ decl, List/*!*/ arguments) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(decl != null); - Contract.Requires(arguments != null); - Contract.Requires(arguments.Count == decl.Arity); - this.Decl = decl; - this.Arguments = arguments; - } - - public bool IsDatatype() { - return QKeyValue.FindBoolAttribute(Decl.Attributes, "datatype"); - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(varMap)); - } - return new CtorType(tok, Decl, newArgs); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - return new CtorType(tok, Decl, newArgs); - } - - //----------- Equality ---------------------------------- - - [Pure] - [Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - Type thatType = that as Type; - if (thatType == null) - return false; - thatType = TypeProxy.FollowProxy(thatType.Expanded); - // shortcut - CtorType thatCtorType = thatType as CtorType; - if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) - return false; - if (Arguments.Count == 0) - return true; - return base.Equals(thatType); - } - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) { - that = TypeProxy.FollowProxy(that.Expanded); - CtorType thatCtorType = that as CtorType; - if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) - return false; - for (int i = 0; i < Arguments.Count; ++i) { - if (!Arguments[i].Equals(thatCtorType.Arguments[i], - thisBoundVariables, thatBoundVariables)) - return false; - } - return true; - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) - return that.Unify(this, unifiableVariables, result); - - CtorType thatCtorType = that as CtorType; - if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) { - return false; - } else { - bool good = true; - for (int i = 0; i < Arguments.Count; ++i) - good &= Arguments[i].Unify(thatCtorType.Arguments[i], unifiableVariables, result); - return good; - } - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - return; - } - - CtorType thatCtorType = that as CtorType; - if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) - throw UNIFICATION_FAILED; - for (int i = 0; i < Arguments.Length; ++i) - Arguments[i].Unify(thatCtorType.Arguments[i], - unifiableVariables, - thisBoundVariables, thatBoundVariables, - result); - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (subst.Count == 0) - return this; - List newArgs = new List(); - lock (Arguments) - { - foreach (Type/*!*/ t in Arguments) - { - Contract.Assert(t != null); - newArgs.Add(t.Substitute(subst)); - } - } - return new CtorType(tok, Decl, newArgs); - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - int res = 1637643879 * Decl.GetHashCode(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - res = res * 3 + t.GetHashCode(boundVariables); - } - return res; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); - } - - internal static void EmitCtorType(string name, List args, TokenTextWriter stream, int contextBindingStrength) { - Contract.Requires(stream != null); - Contract.Requires(args != null); - Contract.Requires(name != null); - int opBindingStrength = args.Count > 0 ? 0 : 2; - if (opBindingStrength < contextBindingStrength) - stream.Write("("); - - stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(name)); - int i = args.Count; - foreach (Type/*!*/ t in args) { - Contract.Assert(t != null); - stream.Write(" "); - // use a lower binding strength for the last argument - // to allow map-types without parentheses - t.Emit(stream, i == 1 ? 1 : 2); - i = i - 1; - } - - if (opBindingStrength < contextBindingStrength) - stream.Write(")"); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - List resolvedArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - resolvedArgs.Add(t.ResolveType(rc)); - } - return new CtorType(tok, Decl, resolvedArgs); - } - - public override List/*!*/ FreeVariables { - get { - List/*!*/ res = new List(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - res.AppendWithoutDups(t.FreeVariables); - } - return res; - } - } - - public override List/*!*/ FreeProxies { - get { - List/*!*/ res = new List(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - AppendWithoutDups(res, t.FreeProxies); - } - return res; - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsCtor { - get { - return true; - } - } - public override CtorType/*!*/ AsCtor { - get { - return this; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitCtorType(this); - } - } - - //===================================================================== - - public class MapType : Type { - // an invariant is that each of the type parameters has to occur as - // free variable in at least one of the arguments - public readonly List/*!*/ TypeParameters; - public readonly List/*!*/ Arguments; - public Type/*!*/ Result; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(TypeParameters != null); - Contract.Invariant(Arguments != null); - Contract.Invariant(Result != null); - } - - - public MapType(IToken/*!*/ token, List/*!*/ typeParameters, List/*!*/ arguments, Type/*!*/ result) - : base(token) { - Contract.Requires(token != null); - Contract.Requires(typeParameters != null); - Contract.Requires(arguments != null); - Contract.Requires(result != null); - - this.TypeParameters = typeParameters; - this.Result = result; - this.Arguments = arguments; - } - - //----------- Cloning ---------------------------------- - // We implement our own clone-method, because bound type variables - // have to be created in the right way. It is /not/ ok to just clone - // everything recursively - - public override Type Clone(IDictionary/*!*/ varMap) { - //Contract.Requires(cce.NonNullElements(varMap)); - Contract.Ensures(Contract.Result() != null); - IDictionary/*!*/ newVarMap = - new Dictionary(); - foreach (KeyValuePair p in varMap) { - Contract.Assert(cce.NonNullElements(p)); - if (!TypeParameters.Contains(p.Key)) - newVarMap.Add(p); - } - - List/*!*/ newTypeParams = new List(); - foreach (TypeVariable/*!*/ var in TypeParameters) { - Contract.Assert(var != null); - TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); - Contract.Assert(newVar != null); - newVarMap.Add(var, newVar); - newTypeParams.Add(newVar); - } - - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.Clone(newVarMap)); - } - Type/*!*/ newResult = Result.Clone(newVarMap); - Contract.Assert(newResult != null); - - return new MapType(this.tok, newTypeParams, newArgs, newResult); - } - - public override Type CloneUnresolved() { - Contract.Ensures(Contract.Result() != null); - List/*!*/ newTypeParams = new List(); - foreach (TypeVariable/*!*/ var in TypeParameters) { - Contract.Assert(var != null); - TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); - Contract.Assert(newVar != null); - newTypeParams.Add(newVar); - } - - List/*!*/ newArgs = new List(); - foreach (Type/*!*/ t in Arguments) { - Contract.Assert(t != null); - newArgs.Add(t.CloneUnresolved()); - } - Type/*!*/ newResult = Result.CloneUnresolved(); - Contract.Assert(newResult != null); - - return new MapType(this.tok, newTypeParams, newArgs, newResult); - } - - //----------- Equality ---------------------------------- - - [Pure] - public override bool Equals(Type/*!*/ that, - List/*!*/ thisBoundVariables, - List/*!*/ thatBoundVariables) - { - that = TypeProxy.FollowProxy(that.Expanded); - MapType thatMapType = that as MapType; - if (thatMapType == null || - this.TypeParameters.Count != thatMapType.TypeParameters.Count || - this.Arguments.Count != thatMapType.Arguments.Count) - return false; - - thisBoundVariables = thisBoundVariables.ToList(); - foreach (TypeVariable/*!*/ var in this.TypeParameters) - { - Contract.Assert(var != null); - thisBoundVariables.Add(var); - } - thatBoundVariables = thatBoundVariables.ToList(); - foreach (TypeVariable/*!*/ var in thatMapType.TypeParameters) - { - Contract.Assert(var != null); - thatBoundVariables.Add(var); - } - - for (int i = 0; i < Arguments.Count; ++i) - { - if (!Arguments[i].Equals(thatMapType.Arguments[i], - thisBoundVariables, thatBoundVariables)) - return false; - } - - return this.Result.Equals(thatMapType.Result, - thisBoundVariables, thatBoundVariables); - } - - //----------- Unification of types ----------- - - public override bool Unify(Type/*!*/ that, - List/*!*/ unifiableVariables, - IDictionary/*!*/ result) { - that = that.Expanded; - if (that is TypeProxy || that is TypeVariable) - return that.Unify(this, unifiableVariables, result); - - MapType thatMapType = that as MapType; - if (thatMapType == null || - this.TypeParameters.Count != thatMapType.TypeParameters.Count || - this.Arguments.Count != thatMapType.Arguments.Count) - return false; - - // treat the bound variables of the two map types as equal... - Dictionary/*!*/ subst0 = - new Dictionary(); - Dictionary/*!*/ subst1 = - new Dictionary(); - List freshies = new List(); - for (int i = 0; i < this.TypeParameters.Count; i++) { - TypeVariable tp0 = this.TypeParameters[i]; - TypeVariable tp1 = thatMapType.TypeParameters[i]; - TypeVariable freshVar = new TypeVariable(tp0.tok, tp0.Name); - freshies.Add(freshVar); - subst0.Add(tp0, freshVar); - subst1.Add(tp1, freshVar); - } - // ... and then unify the domain and range types - bool good = true; - for (int i = 0; i < this.Arguments.Count; i++) { - Type t0 = this.Arguments[i].Substitute(subst0); - Type t1 = thatMapType.Arguments[i].Substitute(subst1); - good &= t0.Unify(t1, unifiableVariables, result); - } - Type r0 = this.Result.Substitute(subst0); - Type r1 = thatMapType.Result.Substitute(subst1); - good &= r0.Unify(r1, unifiableVariables, result); - - // Finally, check that none of the bound variables has escaped - if (good && freshies.Count != 0) { - // This is done by looking for occurrences of the fresh variables in the - // non-substituted types ... - List freeVars = this.FreeVariables; - foreach (TypeVariable fr in freshies) - if (freeVars.Contains(fr)) { - return false; - } // fresh variable escaped - freeVars = thatMapType.FreeVariables; - foreach (TypeVariable fr in freshies) - if (freeVars.Contains(fr)) { - return false; - } // fresh variable escaped - - // ... and in the resulting unifier of type variables - foreach (KeyValuePair pair in result) { - Contract.Assert(cce.NonNullElements(pair)); - freeVars = pair.Value.FreeVariables; - foreach (TypeVariable fr in freshies) - if (freeVars.Contains(fr)) { - return false; - } // fresh variable escaped - } - } - - return good; - } - -#if OLD_UNIFICATION - public override void Unify(Type! that, - List! unifiableVariables, - List! thisBoundVariables, - List! thatBoundVariables, - IDictionary! result) { - that = that.Expanded; - if (that is TypeVariable) { - that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); - return; - } - - MapType thatMapType = that as MapType; - if (thatMapType == null || - this.TypeParameters.Length != thatMapType.TypeParameters.Length || - this.Arguments.Length != thatMapType.Arguments.Length) - throw UNIFICATION_FAILED; - - // ensure that no collisions occur - if (this.collisionsPossible(result)) { - ((MapType)this.Clone()) - .Unify(that, unifiableVariables, - thisBoundVariables, thatBoundVariables, result); - return; - } - if (thatMapType.collisionsPossible(result)) - thatMapType = (MapType)that.Clone(); - - foreach(TypeVariable/*!*/ var in this.TypeParameters){ -Contract.Assert(var != null); - thisBoundVariables.Add(var);} - foreach(TypeVariable/*!*/ var in thatMapType.TypeParameters){ -Contract.Assert(var != null); - thatBoundVariables.Add(var);} - - try { - - for (int i = 0; i < Arguments.Length; ++i) - Arguments[i].Unify(thatMapType.Arguments[i], - unifiableVariables, - thisBoundVariables, thatBoundVariables, - result); - Result.Unify(thatMapType.Result, - unifiableVariables, - thisBoundVariables, thatBoundVariables, - result); - - } finally { - // make sure that the bound variables are removed again - for (int i = 0; i < this.TypeParameters.Length; ++i) { - thisBoundVariables.Remove(); - thatBoundVariables.Remove(); - } - } - } -#endif - - //----------- Substitution of free variables with types not containing bound variables ----------------- - - [Pure] - private bool collisionsPossible(IDictionary/*!*/ subst) { - Contract.Requires(cce.NonNullDictionaryAndValues(subst)); - // PR: could be written more efficiently - return TypeParameters.Any(param => subst.ContainsKey(param) || subst.Values.Any(val => val.FreeVariables.Contains(param))); - } - - public override Type Substitute(IDictionary/*!*/ subst) { - //Contract.Requires(cce.NonNullElements(subst)); - Contract.Ensures(Contract.Result() != null); - if (subst.Count == 0) - return this; - - // there are two cases in which we have to be careful: - // * a variable to be substituted is shadowed by a variable binder - // * a substituted term contains variables that are bound in the - // type (variable capture) - // - // in both cases, we first clone the type to ensure that bound - // variables are fresh - - if (collisionsPossible(subst)) { - MapType/*!*/ newType = (MapType)this.Clone(); - Contract.Assert(newType != null); - Contract.Assert(newType.Equals(this) && !newType.collisionsPossible(subst)); - return newType.Substitute(subst); - } - - List newArgs = new List(); - lock (Arguments) - { - foreach (Type/*!*/ t in Arguments) - { - Contract.Assert(t != null); - newArgs.Add(t.Substitute(subst)); - } - } - Type/*!*/ newResult = Result.Substitute(subst); - Contract.Assert(newResult != null); - - return new MapType(tok, TypeParameters, newArgs, newResult); - } - - //----------- Hashcodes ---------------------------------- - - [Pure] - public override int GetHashCode(List boundVariables) { - //Contract.Requires(boundVariables != null); - int res = 7643761 * TypeParameters.Count + 65121 * Arguments.Count; - - boundVariables = boundVariables.ToList(); - foreach (TypeVariable/*!*/ var in this.TypeParameters) { - Contract.Assert(var != null); - boundVariables.Add(var); - } - - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - res = res * 5 + t.GetHashCode(boundVariables); - } - res = res * 7 + Result.GetHashCode(boundVariables); - - return res; - } - - //----------- Linearisation ---------------------------------- - - public override void Emit(TokenTextWriter stream, int contextBindingStrength) { - //Contract.Requires(stream != null); - stream.SetToken(this); - - const int opBindingStrength = 1; - if (opBindingStrength < contextBindingStrength) - stream.Write("("); - - EmitOptionalTypeParams(stream, TypeParameters); - - stream.Write("["); - Arguments.Emit(stream, ","); // default binding strength of 0 is ok - stream.Write("]"); - Result.Emit(stream); // default binding strength of 0 is ok - - if (opBindingStrength < contextBindingStrength) - stream.Write(")"); - } - - //----------- Resolution ---------------------------------- - - public override Type ResolveType(ResolutionContext rc) { - //Contract.Requires(rc != null); - Contract.Ensures(Contract.Result() != null); - int previousState = rc.TypeBinderState; - try { - foreach (TypeVariable/*!*/ v in TypeParameters) { - Contract.Assert(v != null); - rc.AddTypeBinder(v); - } - - List resolvedArgs = new List(); - foreach (Type/*!*/ ty in Arguments) { - Contract.Assert(ty != null); - resolvedArgs.Add(ty.ResolveType(rc)); - } - - Type resolvedResult = Result.ResolveType(rc); - - CheckBoundVariableOccurrences(TypeParameters, - resolvedArgs, new List { resolvedResult }, - this.tok, "map arguments", - rc); - - // sort the type parameters so that they are bound in the order of occurrence - List/*!*/ sortedTypeParams = SortTypeParams(TypeParameters, resolvedArgs, resolvedResult); - Contract.Assert(sortedTypeParams != null); - return new MapType(tok, sortedTypeParams, resolvedArgs, resolvedResult); - } finally { - rc.TypeBinderState = previousState; - } - } - - public override List/*!*/ FreeVariables { - get { - List/*!*/ res = FreeVariablesIn(Arguments.ToList()); - Contract.Assert(res != null); - res.AppendWithoutDups(Result.FreeVariables); - foreach (TypeVariable/*!*/ v in TypeParameters.ToArray()) { - Contract.Assert(v != null); - res.Remove(v); - } - return res; - } - } - - public override List/*!*/ FreeProxies { - get { - List/*!*/ res = new List(); - foreach (Type/*!*/ t in Arguments.ToArray()) { - Contract.Assert(t != null); - AppendWithoutDups(res, t.FreeProxies); - } - AppendWithoutDups(res, Result.FreeProxies); - return res; - } - } - - //----------- Getters/Issers ---------------------------------- - - public override bool IsMap { - get { - return true; - } - } - public override MapType/*!*/ AsMap { - get { - return this; - } - } - public override int MapArity { - get { - return Arguments.Count; - } - } - - //------------ Match formal argument types of the map - //------------ on concrete types, substitute the result into the - //------------ result type. Null is returned if so many type checking - //------------ errors occur that the situation is hopeless - - public Type CheckArgumentTypes(List/*!*/ actualArgs, - out TypeParamInstantiation/*!*/ tpInstantiation, - IToken/*!*/ typeCheckingSubject, - string/*!*/ opName, - TypecheckingContext/*!*/ tc) { - Contract.Requires(actualArgs != null); - Contract.Requires(typeCheckingSubject != null); - - Contract.Requires(opName != null); - Contract.Requires(tc != null); -Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); - List/*!*/ actualTypeParams; - List actualResult = - Type.CheckArgumentTypes(TypeParameters, out actualTypeParams, Arguments, actualArgs, - new List { Result }, null, typeCheckingSubject, opName, tc); - if (actualResult == null) { - tpInstantiation = SimpleTypeParamInstantiation.EMPTY; - return null; - } else { - Contract.Assert(actualResult.Count == 1); - tpInstantiation = SimpleTypeParamInstantiation.From(TypeParameters, actualTypeParams); - return actualResult[0]; - } - } - - public override Absy StdDispatch(StandardVisitor visitor) { - //Contract.Requires(visitor != null); - Contract.Ensures(Contract.Result() != null); - return visitor.VisitMapType(this); - } - } - - //--------------------------------------------------------------------- - - public enum SimpleType { - Int, - Real, - Bool - }; - - - //===================================================================== - - // Interface for representing the instantiations of type parameters of - // polymorphic functions or maps. We introduce an own interface for this - // instead of using a simple list or dictionary, because in some cases - // (due to the type proxies for map types) the actual number and instantiation - // of type parameters can only be determined very late. - [ContractClass(typeof(TypeParamInstantiationContracts))] - public interface TypeParamInstantiation { - // return what formal type parameters there are - List/*!*/ FormalTypeParams { - get; - } - // given a formal type parameter, return the actual instantiation - Type/*!*/ this[TypeVariable/*!*/ var] { - get; - } - } - [ContractClassFor(typeof(TypeParamInstantiation))] - public abstract class TypeParamInstantiationContracts : TypeParamInstantiation { - #region TypeParamInstantiation Members - - public List FormalTypeParams { - - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - throw new NotImplementedException(); - } - } - - public Type this[TypeVariable var] { - get { - Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - - throw new NotImplementedException(); - } - } - - #endregion - } - - - public class SimpleTypeParamInstantiation : TypeParamInstantiation { - private readonly List/*!*/ TypeParams; - [ContractInvariantMethod] - void TypeParamsInvariantMethod() { - Contract.Invariant(cce.NonNullElements(TypeParams)); - } - private readonly IDictionary/*!*/ Instantiations; - [ContractInvariantMethod] - void InstantiationsInvariantMethod() { - Contract.Invariant(cce.NonNullDictionaryAndValues(Instantiations)); - } - - public SimpleTypeParamInstantiation(List/*!*/ typeParams, - IDictionary/*!*/ instantiations) { - Contract.Requires(cce.NonNullElements(typeParams)); - Contract.Requires(cce.NonNullDictionaryAndValues(instantiations)); - this.TypeParams = typeParams; - this.Instantiations = instantiations; - } - - public static TypeParamInstantiation/*!*/ From(List typeParams, List/*!*/ actualTypeParams) { - Contract.Requires(cce.NonNullElements(actualTypeParams)); - Contract.Requires(typeParams != null); - Contract.Requires(typeParams.Count == actualTypeParams.Count); - Contract.Ensures(Contract.Result() != null); - - if (typeParams.Count == 0) - return EMPTY; - - List/*!*/ typeParamList = new List(); - IDictionary/*!*/ dict = new Dictionary(); - for (int i = 0; i < typeParams.Count; ++i) { - typeParamList.Add(typeParams[i]); - dict.Add(typeParams[i], actualTypeParams[i]); - } - return new SimpleTypeParamInstantiation(typeParamList, dict); - } - - public static readonly TypeParamInstantiation EMPTY = - new SimpleTypeParamInstantiation(new List(), - new Dictionary()); - - // return what formal type parameters there are - public List/*!*/ FormalTypeParams { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - return TypeParams; - } - } - // given a formal type parameter, return the actual instantiation - public Type/*!*/ this[TypeVariable/*!*/ var] { - get { - return Instantiations[var]; - } - } - } - - // Implementation of TypeParamInstantiation that refers to the current - // value of a MapTypeProxy. This means that the values return by the - // methods of this implementation can change in case the MapTypeProxy - // receives further unifications. - class MapTypeProxyParamInstantiation : TypeParamInstantiation { - private readonly MapTypeProxy/*!*/ Proxy; - - // the argument and result type of this particular usage of the map - // type. these are necessary to derive the values of the type parameters - private readonly List/*!*/ ArgumentsResult; - - // field that is initialised once all necessary information is available - // (the MapTypeProxy is instantiated to an actual type) and the instantiation - // of a type parameter is queried - private IDictionary Instantiations = null; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Proxy != null); - Contract.Invariant(ArgumentsResult != null); - Contract.Invariant(Instantiations == null || cce.NonNullDictionaryAndValues(Instantiations)); - } - - - public MapTypeProxyParamInstantiation(MapTypeProxy/*!*/ proxy, - List/*!*/ argumentsResult) { - Contract.Requires(proxy != null); - Contract.Requires(argumentsResult != null); - this.Proxy = proxy; - this.ArgumentsResult = argumentsResult; - } - - // return what formal type parameters there are - public List/*!*/ FormalTypeParams { - get { - MapType realType = Proxy.ProxyFor as MapType; - if (realType == null) - // no instantiation of the map type is known, which means - // that the map type is assumed to be monomorphic - return new List(); - else - return realType.TypeParameters.ToList(); - } - } - - // given a formal type parameter, return the actual instantiation - public Type/*!*/ this[TypeVariable/*!*/ var] { - get { - // then there has to be an instantiation that is a polymorphic map type - if (Instantiations == null) { - MapType realType = Proxy.ProxyFor as MapType; - Contract.Assert(realType != null); - List/*!*/ formalArgs = new List(); - foreach (Type/*!*/ t in realType.Arguments) { - Contract.Assert(t != null); - formalArgs.Add(t); - } - formalArgs.Add(realType.Result); - Instantiations = - Type.InferTypeParameters(realType.TypeParameters, formalArgs, ArgumentsResult); - } - return Instantiations[var]; - } - } - } +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// BoogiePL - Absy.cs +//--------------------------------------------------------------------------------------------- + +namespace Microsoft.Boogie { + using System; + using System.Collections; + using System.Diagnostics; + using System.Linq; + using System.Collections.Generic; + using Microsoft.Boogie.AbstractInterpretation; + using System.Diagnostics.Contracts; + + //===================================================================== + //--------------------------------------------------------------------- + // Types + [ContractClass(typeof(TypeContracts))] + public abstract class Type : Absy { + public Type(IToken/*!*/ token) + : base(token) { + Contract.Requires(token != null); + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. Applying Clone to a type will return + // a type in which all bound variables have been replaced with new + // variables, whereas free variables have not changed + + public override Absy Clone() { + Contract.Ensures(Contract.Result() != null); + return this.Clone(new Dictionary()); + } + + public abstract Type/*!*/ Clone(IDictionary/*!*/ varMap); + + /// + /// Clones the type, but only syntactically. Anything resolved in the source + /// type is left unresolved (that is, with just the name) in the destination type. + /// + public abstract Type/*!*/ CloneUnresolved(); + + //----------- Linearisation ---------------------------------- + + public void Emit(TokenTextWriter stream) { + Contract.Requires(stream != null); + this.Emit(stream, 0); + } + + public abstract void Emit(TokenTextWriter/*!*/ stream, int contextBindingStrength); + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, /*setTokens=*/false, /*pretty=*/ false)) { + this.Emit(stream); + } + return buffer.ToString(); + } + + //----------- Equality ---------------------------------- + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (ReferenceEquals(this, that)) + return true; + Type thatType = that as Type; + return thatType != null && this.Equals(thatType, + new List(), + new List()); + } + + [Pure] + public abstract bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables); + + // used to skip leading type annotations (subexpressions of the + // resulting type might still contain annotations) + internal virtual Type/*!*/ Expanded { + get { + Contract.Ensures(Contract.Result() != null); + + return this; + } + } + + //----------- Unification of types ----------- + + /// + /// Add a constraint that this==that, if possible, and return true. + /// If not possible, return false (which may have added some partial constraints). + /// No error is printed. + /// + public bool Unify(Type that) { + Contract.Requires(that != null); + return Unify(that, new List(), new Dictionary()); + } + + public abstract bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier); + + + [Pure] + public static bool IsIdempotent(IDictionary/*!*/ unifier) { + Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); + return unifier.Values.All(val => val.FreeVariables.All(var => !unifier.ContainsKey(var))); + } + + +#if OLD_UNIFICATION + // Compute a most general unification of two types. null is returned if + // no such unifier exists. The unifier is not allowed to subtitute any + // type variables other than the ones in "unifiableVariables" + public IDictionary Unify(Type! that, + List! unifiableVariables) { + Dictionary! result = new Dictionary (); + try { + this.Unify(that, unifiableVariables, + new List (), new List (), result); + } catch (UnificationFailedException) { + return null; + } + return result; + } + + // Compute an idempotent most general unifier and add the result to the argument + // unifier. The result is true iff the unification succeeded + public bool Unify(Type! that, + List! unifiableVariables, + // given mappings that need to be taken into account + // the old unifier has to be idempotent as well + IDictionary! unifier) + { + Contract.Requires(Contract.ForAll(unifier.Keys , key=> unifiableVariables.Has(key))); + Contract.Requires(IsIdempotent(unifier)); + try { + this.Unify(that, unifiableVariables, + new List (), new List (), unifier); + } catch (UnificationFailedException) { + return false; + } + return true; + } + + public abstract void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary! result); +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public abstract Type/*!*/ Substitute(IDictionary/*!*/ subst); + + //----------- Hashcodes ---------------------------------- + + // Hack to be able to access the hashcode of superclasses further up + // (from the subclasses of this class) + [Pure] + protected int GetBaseHashCode() { + return base.GetHashCode(); + } + + [Pure] + public override int GetHashCode() { + return this.GetHashCode(new List()); + } + + [Pure] + public abstract int GetHashCode(List/*!*/ boundVariables); + + //----------- Resolution ---------------------------------- + + public override void Resolve(ResolutionContext rc) { + //Contract.Requires(rc != null); + System.Diagnostics.Debug.Fail("Type.Resolve should never be called." + + " Use Type.ResolveType instead"); + } + + public abstract Type/*!*/ ResolveType(ResolutionContext/*!*/ rc); + + public override void Typecheck(TypecheckingContext tc) { + //Contract.Requires(tc != null); + System.Diagnostics.Debug.Fail("Type.Typecheck should never be called"); + } + + // determine the free variables in a type, in the order in which the variables occur + public abstract List/*!*/ FreeVariables { + get; + } + + // determine the free type proxies in a type, in the order in which they occur + public abstract List/*!*/ FreeProxies { + get; + } + + protected static void AppendWithoutDups(List a, List b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + foreach (A x in b) + if (!a.Contains(x)) + a.Add(x); + } + + public bool IsClosed { + get { + return FreeVariables.Count == 0; + } + } + + //----------- Getters/Issers ---------------------------------- + + // the following methods should be used instead of simple casts or the + // C# "is" operator, because they handle type synonym annotations and + // type proxies correctly + + public virtual bool IsBasic { + get { + return false; + } + } + public virtual bool IsInt { + get { + return false; + } + } + public virtual bool IsReal { + get { + return false; + } + } + public virtual bool IsBool { + get { + return false; + } + } + + public virtual bool IsVariable { + get { + return false; + } + } + public virtual TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsVariable should never be called + } + } + public virtual bool IsCtor { + get { + return false; + } + } + public virtual CtorType/*!*/ AsCtor { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsCtor should never be called + } + } + public virtual bool IsMap { + get { + return false; + } + } + public virtual MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsMap should never be called + } + } + public virtual int MapArity { + get { + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.MapArity should never be called + } + } + public virtual bool IsUnresolved { + get { + return false; + } + } + public virtual UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.AsUnresolved should never be called + } + } + + public virtual bool IsBv { + get { + return false; + } + } + public virtual int BvBits { + get { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // Type.BvBits should never be called + } + } + + public static readonly Type/*!*/ Int = new BasicType(SimpleType.Int); + public static readonly Type/*!*/ Real = new BasicType(SimpleType.Real); + public static readonly Type/*!*/ Bool = new BasicType(SimpleType.Bool); + private static BvType[] bvtypeCache; + + static public BvType GetBvType(int sz) { + Contract.Requires(0 <= sz); + Contract.Ensures(Contract.Result() != null); + + if (bvtypeCache == null) { + bvtypeCache = new BvType[128]; + } + if (sz < bvtypeCache.Length) { + BvType t = bvtypeCache[sz]; + if (t == null) { + t = new BvType(sz); + bvtypeCache[sz] = t; + } + return t; + } else { + return new BvType(sz); + } + } + + //------------ Match formal argument types on actual argument types + //------------ and return the resulting substitution of type variables + +#if OLD_UNIFICATION + public static IDictionary! + MatchArgumentTypes(List! typeParams, + List! formalArgs, + List! actualArgs, + List formalOuts, + List actualOuts, + string! opName, + TypecheckingContext! tc) + { + Contract.Requires(formalArgs.Length == actualArgs.Length); + Contract.Requires(formalOuts == null <==> actualOuts == null); + Contract.Requires(formalOuts != null ==> formalOuts.Length == actualOuts.Length); + List! boundVarSeq0 = new List (); + List! boundVarSeq1 = new List (); + Dictionary! subst = new Dictionary(); + + for (int i = 0; i < formalArgs.Length; ++i) { + try { + Type! actualType = cce.NonNull((!)actualArgs[i]).Type; + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(forall{TypeVariable! var in typeParams); + !actualType.FreeVariables.Has(var)}; + formalArgs[i].Unify(actualType, + typeParams, + boundVarSeq0, boundVarSeq1, + subst); + } catch (UnificationFailedException) { + tc.Error(actualArgs[i], + "invalid type for argument {0} in {1}: {2} (expected: {3})", + i, opName, actualArgs[i].Type, + // we insert the type parameters that have already been + // chosen to get a more precise error message + formalArgs[i].Substitute(subst)); + // the bound variable sequences should be empty ... + // so that we can continue with the unification + Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); + } + } + + if (formalOuts != null) { + for (int i = 0; i < formalOuts.Length; ++i) { + try { + Type! actualType = cce.NonNull((!)actualOuts[i]).Type; + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(forall{TypeVariable! var in typeParams); + !actualType.FreeVariables.Has(var)}; + formalOuts[i].Unify(actualType, + typeParams, + boundVarSeq0, boundVarSeq1, + subst); + } catch (UnificationFailedException) { + tc.Error(actualOuts[i], + "invalid type for result {0} in {1}: {2} (expected: {3})", + i, opName, actualOuts[i].Type, + // we insert the type parameters that have already been + // chosen to get a more precise error message + formalOuts[i].Substitute(subst)); + // the bound variable sequences should be empty ... + // so that we can continue with the unification + Contract.Assert(boundVarSeq0.Length == 0 && boundVarSeq1.Length == 0); + } + } + } + + // we only allow type parameters to be substituted + Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); + + return subst; + } +#else + public static IDictionary/*!*/ + MatchArgumentTypes(List/*!*/ typeParams, + List/*!*/ formalArgs, + IList/*!*/ actualArgs, + List formalOuts, + List actualOuts, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) { + Contract.Requires(typeParams != null); + Contract.Requires(formalArgs != null); + Contract.Requires(actualArgs != null); + Contract.Requires(opName != null); + Contract.Requires(tc != null); + Contract.Requires(formalArgs.Count == actualArgs.Count); + Contract.Requires((formalOuts == null) == (actualOuts == null)); + Contract.Requires(formalOuts == null || formalOuts.Count == cce.NonNull(actualOuts).Count); + Contract.Requires(tc == null || opName != null);//Redundant + Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); + + // requires "actualArgs" and "actualOuts" to have been type checked + + Dictionary subst = new Dictionary(); + foreach (TypeVariable/*!*/ tv in typeParams) { + Contract.Assert(tv != null); + TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); + subst.Add(tv, proxy); + } + + for (int i = 0; i < formalArgs.Count; i++) { + Type formal = formalArgs[i].Substitute(subst); + Type actual = cce.NonNull(cce.NonNull(actualArgs[i]).Type); + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); + + if (!formal.Unify(actual)) { + Contract.Assume(tc != null); // caller expected no errors + Contract.Assert(opName != null); // follows from precondition + tc.Error(cce.NonNull(actualArgs[i]), + "invalid type for argument {0} in {1}: {2} (expected: {3})", + i, opName, actual, formalArgs[i]); + } + } + + if (formalOuts != null) { + for (int i = 0; i < formalOuts.Count; ++i) { + Type formal = formalOuts[i].Substitute(subst); + Type actual = cce.NonNull(cce.NonNull(actualOuts)[i].Type); + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !actual.FreeVariables.Contains(typeParams[var]))); + + if (!formal.Unify(actual)) { + Contract.Assume(tc != null); // caller expected no errors + Contract.Assert(opName != null); // follows from precondition + tc.Error(actualOuts[i], + "invalid type for out-parameter {0} in {1}: {2} (expected: {3})", + i, opName, actual, formal); + } + } + } + + return subst; + } +#endif + + //------------ Match formal argument types of a function or map + //------------ on concrete types, substitute the result into the + //------------ result type. Null is returned for type errors + + public static List CheckArgumentTypes(List/*!*/ typeParams, + out List/*!*/ actualTypeParams, + List/*!*/ formalIns, + IList/*!*/ actualIns, + List/*!*/ formalOuts, + List actualOuts, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) + // requires "actualIns" and "actualOuts" to have been type checked + { + Contract.Requires(typeParams != null); + + Contract.Requires(formalIns != null); + Contract.Requires(formalOuts != null); + Contract.Requires(actualIns != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null);Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out actualTypeParams))); + actualTypeParams = new List(); + + if (formalIns.Count != actualIns.Count) { + tc.Error(typeCheckingSubject, "wrong number of arguments in {0}: {1}", + opName, actualIns.Count); + // if there are no type parameters, we can still return the result + // type and hope that the type checking proceeds + return typeParams.Count == 0 ? formalOuts : null; + } else if (actualOuts != null && formalOuts.Count != actualOuts.Count) { + tc.Error(typeCheckingSubject, "wrong number of result variables in {0}: {1}", + opName, actualOuts.Count); + // if there are no type parameters, we can still return the result + // type and hope that the type checking proceeds + actualTypeParams = new List(); + return typeParams.Count == 0 ? formalOuts : null; + } + + int previousErrorCount = tc.ErrorCount; + IDictionary subst = + MatchArgumentTypes(typeParams, formalIns, actualIns, + actualOuts != null ? formalOuts : null, actualOuts, opName, tc); + Contract.Assert(cce.NonNullDictionaryAndValues(subst)); + foreach (TypeVariable/*!*/ var in typeParams) { + Contract.Assert(var != null); + actualTypeParams.Add(subst[var]); + } + + List/*!*/ actualResults = new List(); + foreach (Type/*!*/ t in formalOuts) { + Contract.Assert(t != null); + actualResults.Add(t.Substitute(subst)); + } + List resultFreeVars = FreeVariablesIn(actualResults); + if (previousErrorCount != tc.ErrorCount) { + // errors occured when matching the formal arguments + // in case we have been able to substitute all type parameters, + // we can still return the result type and hope that the + // type checking proceeds in a meaningful manner + if (typeParams.All(param => !resultFreeVars.Contains(param))) + return actualResults; + else + // otherwise there is no point in returning the result type, + // type checking would only get confused even further + return null; + } + + Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !resultFreeVars.Contains(typeParams[index]))); + return actualResults; + } + + /////////////////////////////////////////////////////////////////////////// + + // about the same as Type.CheckArgumentTypes, but without + // detailed error reports + public static Type/*!*/ InferValueType(List/*!*/ typeParams, + List/*!*/ formalArgs, + Type/*!*/ formalResult, + List/*!*/ actualArgs) { + Contract.Requires(typeParams != null); + Contract.Requires(formalArgs != null); + Contract.Requires(formalResult != null); + Contract.Requires(actualArgs != null); + Contract.Ensures(Contract.Result() != null); + + IDictionary/*!*/ subst = + InferTypeParameters(typeParams, formalArgs, actualArgs); + Contract.Assert(cce.NonNullDictionaryAndValues(subst)); + + Type/*!*/ res = formalResult.Substitute(subst); + Contract.Assert(res != null); + // all type parameters have to be substituted with concrete types + List/*!*/ resFreeVars = res.FreeVariables; + Contract.Assert(resFreeVars != null); + Contract.Assert(Contract.ForAll(0, typeParams.Count, var => !resFreeVars.Contains(typeParams[var]))); + return res; + } + +#if OLD_UNIFICATION + public static IDictionary! + InferTypeParameters(List! typeParams, + List! formalArgs, + List! actualArgs) + { + Contract.Requires(formalArgs.Length == actualArgs.Length); + + List! boundVarSeq0 = new List (); + List! boundVarSeq1 = new List (); + Dictionary! subst = new Dictionary(); + + for (int i = 0; i < formalArgs.Length; ++i) { + try { + Contract.Assert(forall{TypeVariable! var in typeParams); + !actualArgs[i].FreeVariables.Has(var)}; + formalArgs[i].Unify(actualArgs[i], typeParams, + boundVarSeq0, boundVarSeq1, subst); + } catch (UnificationFailedException) { + System.Diagnostics.Debug.Fail("Type unification failed: " + + formalArgs[i] + " vs " + actualArgs[i]); + } + } + + // we only allow type parameters to be substituted + Contract.Assert(Contract.ForAll(subst.Keys , var=> typeParams.Has(var))); + return subst; + } +#else + /// + /// like Type.CheckArgumentTypes, but assumes no errors + /// (and only does arguments, not results; and takes actuals as List, not List) + /// + public static IDictionary/*!*/ + InferTypeParameters(List/*!*/ typeParams, + List/*!*/ formalArgs, + List/*!*/ actualArgs) { + Contract.Requires(typeParams != null); + Contract.Requires(formalArgs != null); + Contract.Requires(actualArgs != null);Contract.Requires(formalArgs.Count == actualArgs.Count); + Contract.Ensures(cce.NonNullDictionaryAndValues(Contract.Result>())); + + + List proxies = new List(); + Dictionary/*!*/ subst = new Dictionary(); + foreach (TypeVariable/*!*/ tv in typeParams) { + Contract.Assert(tv != null); + TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); + proxies.Add(proxy); + subst.Add(tv, proxy); + } + + for (int i = 0; i < formalArgs.Count; i++) { + Type formal = formalArgs[i].Substitute(subst); + Type actual = actualArgs[i]; + // if the type variables to be matched occur in the actual + // argument types, something has gone very wrong + Contract.Assert(Contract.ForAll(0, typeParams.Count, index => !actual.FreeVariables.Contains(typeParams[index]))); + + if (!formal.Unify(actual)) { + Contract.Assume(false); // caller expected no errors + } + } + + return subst; + } +#endif + + //----------- Helper methods to deal with bound type variables --------------- + + public static void EmitOptionalTypeParams(TokenTextWriter stream, List typeParams) { + Contract.Requires(typeParams != null); + Contract.Requires(stream != null); + if (typeParams.Count > 0) { + stream.Write("<"); + typeParams.Emit(stream, ","); // default binding strength of 0 is ok + stream.Write(">"); + } + } + + // Sort the type parameters according to the order of occurrence in the argument types + public static List/*!*/ SortTypeParams(List/*!*/ typeParams, List/*!*/ argumentTypes, Type resultType) { + Contract.Requires(typeParams != null); + Contract.Requires(argumentTypes != null); + Contract.Ensures(Contract.Result>() != null); + + Contract.Ensures(Contract.Result>().Count == typeParams.Count); + if (typeParams.Count == 0) { + return typeParams; + } + + List freeVarsInUse = FreeVariablesIn(argumentTypes); + if (resultType != null) { + freeVarsInUse.AppendWithoutDups(resultType.FreeVariables); + } + // "freeVarsInUse" is already sorted, but it may contain type variables not in "typeParams". + // So, project "freeVarsInUse" onto "typeParams": + List sortedTypeParams = new List(); + foreach (TypeVariable/*!*/ var in freeVarsInUse) { + Contract.Assert(var != null); + if (typeParams.Contains(var)) { + sortedTypeParams.Add(var); + } + } + + if (sortedTypeParams.Count < typeParams.Count) + // add the type parameters not mentioned in "argumentTypes" in + // the end of the list (this can happen for quantifiers) + sortedTypeParams.AppendWithoutDups(typeParams); + + return sortedTypeParams; + } + + // Check that each of the type parameters occurs in at least one argument type. + // Return true if some type parameters appear only among "moreArgumentTypes" and + // not in "argumentTypes". + [Pure] + public static bool CheckBoundVariableOccurrences(List/*!*/ typeParams, + List/*!*/ argumentTypes, + List moreArgumentTypes, + IToken/*!*/ resolutionSubject, + string/*!*/ subjectName, + ResolutionContext/*!*/ rc) { + Contract.Requires(typeParams != null); + Contract.Requires(argumentTypes != null); + Contract.Requires(resolutionSubject != null); + Contract.Requires(subjectName != null); + Contract.Requires(rc != null); + List freeVarsInArgs = FreeVariablesIn(argumentTypes); + List moFreeVarsInArgs = moreArgumentTypes == null ? null : FreeVariablesIn(moreArgumentTypes); + bool someTypeParamsAppearOnlyAmongMo = false; + foreach (TypeVariable/*!*/ var in typeParams) { + Contract.Assert(var != null); + if (rc.LookUpTypeBinder(var.Name) == var) // avoid to complain twice about variables that are bound multiple times + { + if (freeVarsInArgs.Contains(var)) { + // cool + } else if (moFreeVarsInArgs != null && moFreeVarsInArgs.Contains(var)) { + someTypeParamsAppearOnlyAmongMo = true; + } else { + rc.Error(resolutionSubject, + "type variable must occur in {0}: {1}", + subjectName, var); + } + } + } + return someTypeParamsAppearOnlyAmongMo; + } + + [Pure] + public static List FreeVariablesIn(List arguments) { + Contract.Requires(arguments != null); + Contract.Ensures(Contract.Result>() != null); + List/*!*/ res = new List(); + foreach (Type/*!*/ t in arguments) { + Contract.Assert(t != null); + res.AppendWithoutDups(t.FreeVariables); + } + return res; + } + } + [ContractClassFor(typeof(Type))] + public abstract class TypeContracts : Type { + public TypeContracts() :base(null){ + + } + public override List FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + throw new NotImplementedException(); + } + } + public override List FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + throw new NotImplementedException(); + } + } + public override Type Clone(IDictionary varMap) { + Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + Contract.Requires(stream != null); + throw new NotImplementedException(); + } + public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { + Contract.Requires(that != null); + Contract.Requires(thisBoundVariables != null); + Contract.Requires(thatBoundVariables != null); + throw new NotImplementedException(); + } + public override bool Unify(Type that, List unifiableVariables, IDictionary unifier) { + Contract.Requires(that != null); + Contract.Requires(unifiableVariables != null); + Contract.Requires(cce.NonNullDictionaryAndValues(unifier)); + Contract.Requires(Contract.ForAll(unifier.Keys, key => unifiableVariables.Contains(key))); + Contract.Requires(IsIdempotent(unifier)); + throw new NotImplementedException(); + } + public override Type Substitute(IDictionary subst) { + Contract.Requires(cce.NonNullDictionaryAndValues(subst)); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override Type ResolveType(ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + public override int GetHashCode(List boundVariables) { + Contract.Requires(boundVariables != null); + throw new NotImplementedException(); + } + } + //===================================================================== + + public class BasicType : Type { + public readonly SimpleType T; + public BasicType(IToken/*!*/ token, SimpleType t) + : base(token) { + Contract.Requires(token != null); + T = t; + } + public BasicType(SimpleType t) + : base(Token.NoToken) { + T = t; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // BasicTypes are immutable anyway, we do not clone + return this; + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + // no parentheses are necessary for basic types + stream.SetToken(this); + stream.Write("{0}", this); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + switch (T) { + case SimpleType.Int: + return "int"; + case SimpleType.Real: + return "real"; + case SimpleType.Bool: + return "bool"; + } + Debug.Assert(false, "bad type " + T); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // make compiler happy + } + + //----------- Equality ---------------------------------- + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + // shortcut + Type thatType = that as Type; + if (thatType == null) + return false; + BasicType thatBasicType = TypeProxy.FollowProxy(thatType.Expanded) as BasicType; + return thatBasicType != null && this.T == thatBasicType.T; + } + + [Pure] + public override bool Equals(Type that, List thisBoundVariables, List thatBoundVariables) { + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(that != null); + return this.Equals(that); + } + + //----------- Unification of types ----------- + + public override bool Unify(Type that, List unifiableVariables, IDictionary/*!*/ unifier) { + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(that != null); + //Contract.Requires(cce.NonNullElements(unifier)); + // an idempotent substitution that describes the + // unification result up to a certain point + + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) { + return that.Unify(this, unifiableVariables, unifier); + } else { + return this.Equals(that); + } + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + } else { + if (!this.Equals(that)) + throw UNIFICATION_FAILED; + } + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + return this.T.GetHashCode(); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + // determine the free variables in a type, in the order in which the variables occur + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return new List(); // basic type are closed + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBasic { + get { + return true; + } + } + public override bool IsInt { + get { + return this.T == SimpleType.Int; + } + } + public override bool IsReal { + get { + return this.T == SimpleType.Real; + } + } + public override bool IsBool { + get { + return this.T == SimpleType.Bool; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBasicType(this); + } + } + + //===================================================================== + + public class BvType : Type { + public readonly int Bits; + + public BvType(IToken token, int bits) + : base(token) { + Contract.Requires(token != null); + Bits = bits; + } + + public BvType(int bits) + : base(Token.NoToken) { + Bits = bits; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively. + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // BvTypes are immutable anyway, we do not clone + return this; + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + // no parentheses are necessary for bitvector-types + stream.SetToken(this); + stream.Write("{0}", this); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result() != null); + return "bv" + Bits; + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + BvType thatBvType = TypeProxy.FollowProxy(that.Expanded) as BvType; + return thatBvType != null && this.Bits == thatBvType.Bits; + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(unifier)); + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) { + return that.Unify(this, unifiableVariables, unifier); + } else { + return this.Equals(that); + } + } + +#if OLD_UNIFICATION + public override void Unify(Type that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary result){ +Contract.Requires(result != null); +Contract.Requires(that != null); + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + } else { + if (!this.Equals(that)) + throw UNIFICATION_FAILED; + } + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + return this.Bits.GetHashCode(); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + // determine the free variables in a type, in the order in which the variables occur + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return new List(); // bitvector-type are closed + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBv { + get { + return true; + } + } + public override int BvBits { + get { + return Bits; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvType(this); + } + } + + //===================================================================== + + // An AST node containing an identifier and a sequence of type arguments, which + // will be turned either into a TypeVariable, into a CtorType or into a BvType + // during the resolution phase + public class UnresolvedTypeIdentifier : Type { + public readonly string/*!*/ Name; + public readonly List/*!*/ Arguments; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + Contract.Invariant(Arguments != null); + } + + + public UnresolvedTypeIdentifier(IToken token, string name) + : this(token, name, new List()) { + Contract.Requires(name != null); + Contract.Requires(token != null); + } + + public UnresolvedTypeIdentifier(IToken token, string name, List arguments) + : base(token) { + Contract.Requires(arguments != null); + Contract.Requires(name != null); + Contract.Requires(token != null); + this.Name = name; + this.Arguments = arguments; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(varMap)); + } + return new UnresolvedTypeIdentifier(tok, Name, newArgs); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + return new UnresolvedTypeIdentifier(tok, Name, newArgs); + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Equals should never be called"); + return false; // to make the compiler happy + } + + //----------- Unification of types ----------- + + public override bool Unify(Type that, + List/*!*/ unifiableVariables, + IDictionary result) { + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(result)); + //Contract.Requires(that != null); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // UnresolvedTypeIdentifier.Unify should never be called + } + +#if OLD_UNIFICATION + public override void Unify(Type that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary result){ +Contract.Requires(result != null); +Contract.Requires(that != null); + System.Diagnostics.Debug.Fail("UnresolvedTypeIdentifier.Unify should never be called"); + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // UnresolvedTypeIdentifier.Substitute should never be called + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // UnresolvedTypeIdentifier.GetHashCode should never be called + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + // first case: the type name denotes a bitvector-type + if (Name.StartsWith("bv") && Name.Length > 2) { + bool is_bv = true; + for (int i = 2; i < Name.Length; ++i) { + if (!char.IsDigit(Name[i])) { + is_bv = false; + break; + } + } + if (is_bv) { + if (Arguments.Count > 0) { + rc.Error(this, + "bitvector types must not be applied to arguments: {0}", + Name); + } + return new BvType(tok, int.Parse(Name.Substring(2))); + } + } + + // second case: the identifier is resolved to a type variable + TypeVariable var = rc.LookUpTypeBinder(Name); + if (var != null) { + if (Arguments.Count > 0) { + rc.Error(this, + "type variables must not be applied to arguments: {0}", + var); + } + return var; + } + + // third case: the identifier denotes a type constructor and we + // recursively resolve the arguments + TypeCtorDecl ctorDecl = rc.LookUpType(Name); + if (ctorDecl != null) { + if (Arguments.Count != ctorDecl.Arity) { + rc.Error(this, + "type constructor received wrong number of arguments: {0}", + ctorDecl); + return this; + } + return new CtorType(tok, ctorDecl, ResolveArguments(rc)); + } + + // fourth case: the identifier denotes a type synonym + TypeSynonymDecl synDecl = rc.LookUpTypeSynonym(Name); + if (synDecl != null) { + if (Arguments.Count != synDecl.TypeParameters.Count) { + rc.Error(this, + "type synonym received wrong number of arguments: {0}", + synDecl); + return this; + } + List/*!*/ resolvedArgs = ResolveArguments(rc); + Contract.Assert(resolvedArgs != null); + + return new TypeSynonymAnnotation(this.tok, synDecl, resolvedArgs); + + } + + // otherwise: this name is not declared anywhere + rc.Error(this, "undeclared type: {0}", Name); + return this; + } + + private List ResolveArguments(ResolutionContext rc) { + Contract.Requires(rc != null); + Contract.Ensures(Contract.Result>() != null); + List/*!*/ resolvedArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + resolvedArgs.Add(t.ResolveType(rc)); + } + return resolvedArgs; + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return new List(); + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + // PR: should unresolved types be syntactically distinguished from resolved types? + CtorType.EmitCtorType(this.Name, Arguments, stream, contextBindingStrength); + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsUnresolved { + get { + return true; + } + } + public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + return this; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitUnresolvedTypeIdentifier(this); + } + } + + //===================================================================== + + public class TypeVariable : Type { + public readonly string/*!*/ Name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + } + + + public TypeVariable(IToken token, string name) + : base(token) { + Contract.Requires(name != null); + Contract.Requires(token != null); + this.Name = name; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + // if this variable is mapped to some new variable, we take the new one + // otherwise, return this + TypeVariable res; + varMap.TryGetValue(this, out res); + if (res == null) + return this; + else + return res; + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return this; + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + TypeVariable thatAsTypeVar = TypeProxy.FollowProxy(that.Expanded) as TypeVariable; + + if (thatAsTypeVar == null) + return false; + + int thisIndex = thisBoundVariables.LastIndexOf(this); + int thatIndex = thatBoundVariables.LastIndexOf(thatAsTypeVar); + return (thisIndex >= 0 && thisIndex == thatIndex) || + (thisIndex == -1 && thatIndex == -1 && + Object.ReferenceEquals(this, thatAsTypeVar)); + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + // an idempotent substitution that describes the + // unification result up to a certain point + IDictionary/*!*/ unifier) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(unifier)); + that = that.Expanded; + if (that is TypeProxy && !(that is ConstrainedProxy)) + return that.Unify(this, unifiableVariables, unifier); + + if (this.Equals(that)) + return true; + + if (unifiableVariables.Contains(this)) { + Type previousSubst; + unifier.TryGetValue(this, out previousSubst); + if (previousSubst == null) { + return addSubstitution(unifier, that); + } else { + // we have to unify the old instantiation with the new one + return previousSubst.Unify(that, unifiableVariables, unifier); + } + } + + // this cannot be instantiated with anything + // but that possibly can ... + + TypeVariable tv = that as TypeVariable; + + return tv != null && + unifiableVariables.Contains(tv) && + that.Unify(this, unifiableVariables, unifier); + } + + // TODO: the following might cause problems, because when applying substitutions + // to type proxies the substitutions are not propagated to the proxy + // constraints (right now at least) + private bool addSubstitution(IDictionary/*!*/ oldSolution, + // the type that "this" is instantiated with + Type/*!*/ newSubst) { + Contract.Requires(cce.NonNullDictionaryAndValues(oldSolution)); + Contract.Requires(newSubst != null); + Contract.Requires(!oldSolution.ContainsKey(this)); + + Dictionary/*!*/ newMapping = new Dictionary(); + // apply the old (idempotent) substitution to the new instantiation + Type/*!*/ substSubst = newSubst.Substitute(oldSolution); + Contract.Assert(substSubst != null); + // occurs check + if (substSubst.FreeVariables.Contains(this)) + return false; + newMapping.Add(this, substSubst); + + // apply the new substitution to the old ones to ensure idempotence + List/*!*/ keys = new List(); + keys.AddRange(oldSolution.Keys); + foreach (TypeVariable/*!*/ var in keys) { + Contract.Assert(var != null); + oldSolution[var] = oldSolution[var].Substitute(newMapping); + } + oldSolution.Add(this, substSubst); + + Contract.Assert(IsIdempotent(oldSolution)); + return true; + } + +#if OLD_UNIFICATION + public override void Unify(Type that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary result){ +Contract.Requires(result != null); +Contract.Requires(that != null); + that = that.Expanded; + int thisIndex = thisBoundVariables.LastIndexOf(this); + if (thisIndex == -1) { + // this is not a bound variable and can possibly be matched on that + // that must not contain any bound variables + List! thatFreeVars = that.FreeVariables; + if (thatBoundVariables.Any(var=> thatFreeVars.Has(var))) + throw UNIFICATION_FAILED; + + // otherwise, in case that is a typevariable it cannot be bound and + // we can just check for equality + if (this.Equals(that)) + return; + + if (!unifiableVariables.Has(this)) { + // this cannot be instantiated with anything + // but that possibly can ... + if ((that is TypeVariable) && + unifiableVariables.Has(that as TypeVariable)) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + return; + } else { + throw UNIFICATION_FAILED; + } + } + + Type previousSubst; + result.TryGetValue(this, out previousSubst); + if (previousSubst == null) { + addSubstitution(result, that); + } else { + // we have to unify the old instantiation with the new one + previousSubst.Unify(that, unifiableVariables, thisBoundVariables, thatBoundVariables, result); + } + } else { + // this is a bound variable, that also has to be one (with the same index) + if (!(that is TypeVariable) || + thatBoundVariables.LastIndexOf(that) != thisIndex) + throw UNIFICATION_FAILED; + } + } + +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + Type res; + if (subst.TryGetValue(this, out res)) { + Contract.Assert(res != null); + return res; + } else { + return this; + } + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + int thisIndex = boundVariables.LastIndexOf(this); + if (thisIndex == -1) + return GetBaseHashCode(); + return thisIndex * 27473671; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + // never put parentheses around variables + stream.SetToken(this); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + //Contract.Ensures(Contract.Result() != null); + // nothing to resolve + return this; + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + return new List { this }; + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return new List(); + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsVariable { + get { + return true; + } + } + public override TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + return this; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + //Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeVariable(this); + } + } + + //===================================================================== + + public class TypeProxy : Type { + static int proxies = 0; + protected readonly string/*!*/ Name; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Name != null); + } + + + public TypeProxy(IToken token, string givenName) + : this(token, givenName, "proxy") { + Contract.Requires(givenName != null); + Contract.Requires(token != null); + } + + protected TypeProxy(IToken token, string givenName, string kind) + : base(token) { + Contract.Requires(kind != null); + Contract.Requires(givenName != null); + Contract.Requires(token != null); + Name = givenName + "$" + kind + "#" + proxies; + proxies++; + } + + private Type proxyFor; + public Type ProxyFor { + // apply path shortening, and then return the value of proxyFor + get { + TypeProxy anotherProxy = proxyFor as TypeProxy; + if (anotherProxy != null && anotherProxy.proxyFor != null) { + // apply path shortening by bypassing "anotherProxy" (and possibly others) + proxyFor = anotherProxy.ProxyFor; + Contract.Assert(proxyFor != null); + } + return proxyFor; + } + } + + [Pure] + [Reads(ReadsAttribute.Reads.Everything)] + public static Type FollowProxy(Type t) { + Contract.Requires(t != null); + Contract.Ensures(Contract.Result() != null); + Contract.Ensures(!(Contract.Result() is TypeProxy) || ((TypeProxy)Contract.Result()).proxyFor == null); + if (t is TypeProxy) { + Type p = ((TypeProxy)t).ProxyFor; + if (p != null) { + return p; + } + } + return t; + } + + protected void DefineProxy(Type ty) { + Contract.Requires(ty != null); + Contract.Requires(ProxyFor == null); + // follow ty down to the leaf level, so that we can avoid creating a cycle + ty = FollowProxy(ty); + if (!object.ReferenceEquals(this, ty)) { + proxyFor = ty; + } + } + + //----------- Cloning ---------------------------------- + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Clone(varMap); + } else { + return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy + } + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return new TypeProxy(this.tok, this.Name); // the clone will have a name that ends with $proxy$proxy + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + //Contract.Requires(that != null); + if (object.ReferenceEquals(this, that)) { + return true; + } + Type p = ProxyFor; + if (p != null) { + return p.Equals(that, thisBoundVariables, thatBoundVariables); + } else { + // This proxy could be made to be equal to anything, so what to return? + return false; + } + } + + //----------- Unification of types ----------- + + // determine whether the occurs check fails: this is a strict subtype of that + protected bool ReallyOccursIn(Type that) { + Contract.Requires(that != null); + that = FollowProxy(that.Expanded); + return that.FreeProxies.Contains(this) && + (that.IsCtor || that.IsMap && this != that && this.ProxyFor != that); + } + + public override bool Unify(Type that, + List/*!*/ unifiableVariables, + IDictionary result) { + //Contract.Requires(cce.NonNullElements(result)); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(that != null); + Type p = ProxyFor; + if (p != null) { + return p.Unify(that, unifiableVariables, result); + } else { + // unify this with that + if (this.ReallyOccursIn(that)) + return false; + DefineProxy(that.Expanded); + return true; + } + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Substitute(subst); + } else { + return this; + } + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + Type p = ProxyFor; + if (p != null) { + return p.GetHashCode(boundVariables); + } else { + return GetBaseHashCode(); + } + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + Type p = ProxyFor; + if (p != null) { + p.Emit(stream, contextBindingStrength); + } else { + // no need for parentheses + stream.SetToken(this); + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(this.Name)); + } + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.ResolveType(rc); + } else { + return this; + } + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + Type p = ProxyFor; + if (p != null) { + return p.FreeVariables; + } else { + return new List(); + } + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + Type p = ProxyFor; + if (p != null) { + return p.FreeProxies; + } else { + List/*!*/ res = new List(); + res.Add(this); + return res; + } + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBasic { + get { + Type p = ProxyFor; + return p != null && p.IsBasic; + } + } + public override bool IsInt { + get { + Type p = ProxyFor; + return p != null && p.IsInt; + } + } + public override bool IsReal { + get { + Type p = ProxyFor; + return p != null && p.IsReal; + } + } + public override bool IsBool { + get { + Type p = ProxyFor; + return p != null && p.IsBool; + } + } + + public override bool IsVariable { + get { + Type p = ProxyFor; + return p != null && p.IsVariable; + } + } + public override TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsVariable; + } + } + + public override bool IsCtor { + get { + Type p = ProxyFor; + return p != null && p.IsCtor; + } + } + public override CtorType/*!*/ AsCtor { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsCtor; + } + } + public override bool IsMap { + get { + Type p = ProxyFor; + return p != null && p.IsMap; + } + } + public override MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsMap; + } + } + public override int MapArity { + get { + Type p = ProxyFor; + Contract.Assume(p != null); + return p.MapArity; + } + } + public override bool IsUnresolved { + get { + Type p = ProxyFor; + return p != null && p.IsUnresolved; + } + } + public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + Contract.Assume(p != null); + return p.AsUnresolved; + } + } + + public override bool IsBv { + get { + Type p = ProxyFor; + return p != null && p.IsBv; + } + } + public override int BvBits { + get { + Type p = ProxyFor; + Contract.Assume(p != null); + return p.BvBits; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeProxy(this); + } + } + + public abstract class ConstrainedProxy : TypeProxy { + protected ConstrainedProxy(IToken token, string givenName, string kind) + : base(token, givenName, kind) { + Contract.Requires(kind != null); + Contract.Requires(givenName != null); + Contract.Requires(token != null); + } + } + + /// + /// Each instance of this class represents a set of bitvector types. In particular, it represents + /// a bitvector type bvN iff + /// minBits ATMOST N and + /// foreach constraint (t0,t1), the types represented by t0 and t1 are bitvector types whose + /// number of bits add up to N. + /// This means that the size of a BvTypeProxy p is constrained not only by p.minBits, but also + /// by the size of various t0 and t1 types that are transitively part of BvTypeProxy constraints. + /// If such a t0 or t1 were to get its ProxyFor field defined, then p would have to be further + /// constrained too. This doesn't seem like it would ever occur in a Boogie 2 program, because: + /// the only place where a BvTypeProxy with constraints can occur is as the type of a + /// BvConcatExpr, and + /// the types of all local variables are explicitly declared, which means that the types of + /// subexpressions of a BvConcatExpr are not going to change other than via the type of the + /// BvConcatExpr. + /// So, this implementation of BvTypeProxy does not keep track of where a BvTypeProxy may occur + /// transitively in some other BvTypeProxy's constraints. + /// + public class BvTypeProxy : ConstrainedProxy { + public int MinBits; + List constraints; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(constraints, true)); + } + + class BvTypeConstraint { + public Type/*!*/ T0; + public Type/*!*/ T1; + public BvTypeConstraint(Type t0, Type t1) { + Contract.Requires(t1 != null); + Contract.Requires(t0 != null); + Contract.Requires(t0.IsBv && t1.IsBv); + T0 = t0; + T1 = t1; + } + } + + public BvTypeProxy(IToken token, string name, int minBits) + : base(token, name, "bv" + minBits + "proxy") { + Contract.Requires(name != null); + Contract.Requires(token != null); + this.MinBits = minBits; + } + + /// + /// Requires that any further constraints to be placed on t0 and t1 go via the object to + /// be constructed. + /// + public BvTypeProxy(IToken token, string name, Type t0, Type t1) + : base(token, name, "bvproxy") { + Contract.Requires(t1 != null); + Contract.Requires(t0 != null); + Contract.Requires(name != null); + Contract.Requires(token != null); + Contract.Requires(t0.IsBv && t1.IsBv); + t0 = FollowProxy(t0); + t1 = FollowProxy(t1); + this.MinBits = MinBitsFor(t0) + MinBitsFor(t1); + List list = new List(); + list.Add(new BvTypeConstraint(t0, t1)); + this.constraints = list; + } + + /// + /// Construct a BvTypeProxy like p, but with minBits. + /// + private BvTypeProxy(BvTypeProxy p, int minBits) + : base(p.tok, p.Name, "") { + Contract.Requires(p != null); + this.MinBits = minBits; + this.constraints = p.constraints; + } + + private BvTypeProxy(IToken token, string name, int minBits, List constraints) + : base(token, name, "") { + Contract.Requires(cce.NonNullElements(constraints, true)); + Contract.Requires(name != null); + Contract.Requires(token != null); + this.MinBits = minBits; + this.constraints = constraints; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Everything)] + private static int MinBitsFor(Type t) { + Contract.Requires(t != null); + Contract.Requires(t.IsBv); + Contract.Ensures(0 <= Contract.Result()); + + if (t is TypeSynonymAnnotation) { + return MinBitsFor(((TypeSynonymAnnotation)t).ExpandedType); + } + + if (t is BvType) { + return t.BvBits; + } else { + return ((BvTypeProxy)t).MinBits; + } + } + + //----------- Cloning ---------------------------------- + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Clone(varMap); + } else { + return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy + } + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + return new BvTypeProxy(this.tok, this.Name, this.MinBits, this.constraints); // the clone will have a name that ends with $bvproxy$bvproxy + } + + //----------- Unification of types ----------- + + public override bool Unify(Type that, + List unifiableVariables, + IDictionary result) { + //Contract.Requires(cce.NonNullElements(result)); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(that != null); + Type p = ProxyFor; + if (p != null) { + return p.Unify(that, unifiableVariables, result); + } + + // unify this with that, if possible + that = that.Expanded; + that = FollowProxy(that); + + if (this.ReallyOccursIn(that)) + return false; + + TypeVariable tv = that as TypeVariable; + + if (tv != null && unifiableVariables.Contains(tv)) + return that.Unify(this, unifiableVariables, result); + + if (object.ReferenceEquals(this, that)) { + return true; + } else if (that is BvType) { + if (MinBits <= that.BvBits) { + if (constraints != null) { + foreach (BvTypeConstraint btc in constraints) { + int minT1 = MinBitsFor(btc.T1); + int left = IncreaseBits(btc.T0, that.BvBits - minT1); + left = IncreaseBits(btc.T1, minT1 + left); + Contract.Assert(left == 0); // because it should always be possible to increase the total size of a BvTypeConstraint pair (t0,t1) arbitrarily + } + } + DefineProxy(that); + return true; + } + } else if (that is BvTypeProxy) { + BvTypeProxy bt = (BvTypeProxy)that; + // keep the proxy with the stronger constraint (that is, the higher minBits), but if either + // has a constraints list, then concatenate both constraints lists and define the previous + // proxies to the new one + if (this.constraints != null || bt.constraints != null) { + List list = new List(); + if (this.constraints != null) { + list.AddRange(this.constraints); + } + if (bt.constraints != null) { + list.AddRange(bt.constraints); + } + BvTypeProxy np = new BvTypeProxy(this.tok, this.Name, Math.Max(this.MinBits, bt.MinBits), list); + this.DefineProxy(np); + bt.DefineProxy(np); + } else if (this.MinBits <= bt.MinBits) { + this.DefineProxy(bt); + } else { + bt.DefineProxy(this); + } + return true; + } else if (that is ConstrainedProxy) { + // only bitvector proxies can be unified with this BvTypeProxy + return false; + } else if (that is TypeProxy) { + // define: that.ProxyFor := this; + return that.Unify(this, unifiableVariables, result); + } + return false; + } + + private static int IncreaseBits(Type t, int to) { + Contract.Requires(t != null); + Contract.Requires(t.IsBv && 0 <= to && MinBitsFor(t) <= to); + Contract.Ensures(0 <= Contract.Result() && Contract.Result() <= to); + + if(t is TypeSynonymAnnotation) { + return IncreaseBits(((TypeSynonymAnnotation)t).ExpandedType, to); + } + + t = FollowProxy(t); + if (t is BvType) { + return to - t.BvBits; + } else { + BvTypeProxy p = (BvTypeProxy)t; + Contract.Assert(p.MinBits <= to); + if (p.MinBits < to) { + BvTypeProxy q = new BvTypeProxy(p, to); + p.DefineProxy(q); + } + return 0; // we were able to satisfy the request completely + } + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (this.ProxyFor == null) { + // check that the constraints are clean and do not contain any + // of the substituted variables (otherwise, we are in big trouble) + Contract.Assert(Contract.ForAll(constraints, c => + Contract.ForAll(subst.Keys, var => + !c.T0.FreeVariables.Contains(var) && !c.T1.FreeVariables.Contains(var)))); + } + return base.Substitute(subst); + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBv { + get { + return true; + } + } + public override int BvBits { + get { + // This method is supposed to return the number of bits supplied, but unless the proxy has been resolved, + // we only have a lower bound on the number of bits supplied. But this method is not supposed to be + // called until type checking has finished, at which time the minBits is stable. + Type p = ProxyFor; + if (p != null) { + return p.BvBits; + } else { + return MinBits; + } + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitBvTypeProxy(this); + } + } + + // Proxy representing map types with a certain arity. Apart from the arity, + // a number of constraints on the index and value type of the map type may + // be known (such constraints result from applied select and store operations). + // Because map type can be polymorphic (in the most general case, each index or + // value type is described by a separate type parameter) any combination of + // constraints can be satisfied. + public class MapTypeProxy : ConstrainedProxy { + public readonly int Arity; + private readonly List/*!*/ constraints = new List(); + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(constraints != null); + } + + + // each constraint specifies that the given combination of argument/result + // types must be a possible instance of the formal map argument/result types + private struct Constraint { + public readonly List/*!*/ Arguments; + public readonly Type/*!*/ Result; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Arguments != null); + Contract.Invariant(Result != null); + } + + + public Constraint(List arguments, Type result) { + Contract.Requires(result != null); + Contract.Requires(arguments != null); + Arguments = arguments; + Result = result; + } + + public Constraint Clone(IDictionary/*!*/ varMap) { + Contract.Requires(cce.NonNullDictionaryAndValues(varMap)); + List/*!*/ args = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + args.Add(t.Clone(varMap)); + } + Type/*!*/ res = Result.Clone(varMap); + Contract.Assert(res != null); + return new Constraint(args, res); + } + + public bool Unify(MapType that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + Contract.Requires(unifiableVariables != null); + Contract.Requires(cce.NonNullDictionaryAndValues(result)); + Contract.Requires(that != null); + Contract.Requires(Arguments.Count == that.Arguments.Count); + Dictionary/*!*/ subst = new Dictionary(); + foreach (TypeVariable/*!*/ tv in that.TypeParameters) { + Contract.Assert(tv != null); + TypeProxy proxy = new TypeProxy(Token.NoToken, tv.Name); + subst.Add(tv, proxy); + } + + bool good = true; + for (int i = 0; i < that.Arguments.Count; i++) { + Type t0 = that.Arguments[i].Substitute(subst); + Type t1 = this.Arguments[i]; + good &= t0.Unify(t1, unifiableVariables, result); + } + good &= that.Result.Substitute(subst).Unify(this.Result, unifiableVariables, result); + return good; + } + } + + public MapTypeProxy(IToken token, string name, int arity) + : base(token, name, "mapproxy") { + Contract.Requires(name != null); + Contract.Requires(token != null); + Contract.Requires(0 <= arity); + this.Arity = arity; + } + + private void AddConstraint(Constraint c) { + Contract.Requires(c.Arguments.Count == Arity); + + Type f = ProxyFor; + MapType mf = f as MapType; + if (mf != null) { + bool success = c.Unify(mf, new List(), new Dictionary()); + Contract.Assert(success); + return; + } + + MapTypeProxy mpf = f as MapTypeProxy; + if (mpf != null) { + mpf.AddConstraint(c); + return; + } + + Contract.Assert(f == null); // no other types should occur as specialisations of this proxy + + constraints.Add(c); + } + + public Type CheckArgumentTypes(List/*!*/ actualArgs, + out TypeParamInstantiation/*!*/ tpInstantiation, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) { + Contract.Requires(actualArgs != null); + Contract.Requires(typeCheckingSubject != null); + Contract.Requires(opName != null); + Contract.Requires(tc != null); + Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + + + + Type f = ProxyFor; + MapType mf = f as MapType; + if (mf != null) + return mf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); + + MapTypeProxy mpf = f as MapTypeProxy; + if (mpf != null) + return mpf.CheckArgumentTypes(actualArgs, out tpInstantiation, typeCheckingSubject, opName, tc); + + Contract.Assert(f == null); // no other types should occur as specialisations of this proxy + + // otherwise, we just record the constraints given by this usage of the map type + List/*!*/ arguments = new List(); + foreach (Expr/*!*/ e in actualArgs) { + Contract.Assert(e != null); + arguments.Add(e.Type); + } + Type/*!*/ result = new TypeProxy(tok, "result"); + Contract.Assert(result != null); + AddConstraint(new Constraint(arguments, result)); + + List/*!*/ argumentsResult = new List(); + foreach (Expr/*!*/ e in actualArgs) { + Contract.Assert(e != null); + argumentsResult.Add(e.Type); + } + argumentsResult.Add(result); + + tpInstantiation = new MapTypeProxyParamInstantiation(this, argumentsResult); + return result; + } + + //----------- Cloning ---------------------------------- + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + Type p = ProxyFor; + if (p != null) { + return p.Clone(varMap); + } else { + MapTypeProxy p2 = new MapTypeProxy(tok, Name, Arity); + foreach (Constraint c in constraints) + p2.AddConstraint(c.Clone(varMap)); + return p2; // the clone will have a name that ends with $mapproxy$mapproxy (hopefully) + } + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + Type p = ProxyFor; + if (p != null) { + p.Emit(stream, contextBindingStrength); + } else { + stream.Write("["); + string/*!*/ sep = ""; + for (int i = 0; i < Arity; ++i) { + stream.Write(sep); + sep = ", "; + stream.Write("?"); + } + stream.Write("]?"); + } + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(result)); + Type p = ProxyFor; + if (p != null) { + return p.Unify(that, unifiableVariables, result); + } + + // unify this with that, if possible + that = that.Expanded; + that = FollowProxy(that); + + if (this.ReallyOccursIn(that)) + return false; + + TypeVariable tv = that as TypeVariable; + + if (tv != null && unifiableVariables.Contains(tv)) + return that.Unify(this, unifiableVariables, result); + + if (object.ReferenceEquals(this, that)) { + return true; + } else if (that is MapType) { + MapType mapType = (MapType)that; + if (mapType.Arguments.Count == Arity) { + bool good = true; + foreach (Constraint c in constraints) + good &= c.Unify(mapType, unifiableVariables, result); + if (good) { + DefineProxy(mapType); + return true; + } + } + } else if (that is MapTypeProxy) { + MapTypeProxy mt = (MapTypeProxy)that; + if (mt.Arity == this.Arity) { + // we propagate the constraints of this proxy to the more specific one + foreach (Constraint c in constraints) + mt.AddConstraint(c); + DefineProxy(mt); + return true; + } + } else if (that is ConstrainedProxy) { + // only map-type proxies can be unified with this MapTypeProxy + return false; + } else if (that is TypeProxy) { + // define: that.ProxyFor := this; + return that.Unify(this, unifiableVariables, result); + } + return false; + } + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (this.ProxyFor == null) { + // check that the constraints are clean and do not contain any + // of the substituted variables (otherwise, we are in big trouble) + Contract.Assert(Contract.ForAll(constraints, c => + Contract.ForAll(subst.Keys, var => + Contract.ForAll(0, c.Arguments.Count, t => !c.Arguments[t].FreeVariables.Contains(var)) && + !c.Result.FreeVariables.Contains(var)))); + } + return base.Substitute(subst); + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsMap { + get { + return true; + } + } + public override MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + + Type p = ProxyFor; + if (p != null) { + return p.AsMap; + } else { + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } // what to do now? + } + } + } + public override int MapArity { + get { + return Arity; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitMapTypeProxy(this); + } + } + + //===================================================================== + + // Used to annotate types with type synoyms that were used in the + // original unresolved types. Such types should be considered as + // equivalent to ExpandedType, the annotations are only used to enable + // better pretty-printing + public class TypeSynonymAnnotation : Type { + public Type/*!*/ ExpandedType; + + public readonly List/*!*/ Arguments; + // is set during resolution and determines whether the right number of arguments is given + public readonly TypeSynonymDecl/*!*/ Decl; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(ExpandedType != null); + Contract.Invariant(Arguments != null); + Contract.Invariant(Decl != null); + } + + + public TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(decl != null); + Contract.Requires(arguments != null); + Contract.Requires(arguments.Count == decl.TypeParameters.Count); + this.Decl = decl; + this.Arguments = arguments; + + // build a substitution that can be applied to the definition of + // the type synonym + IDictionary/*!*/ subst = + new Dictionary(); + for (int i = 0; i < arguments.Count; ++i) + subst.Add(decl.TypeParameters[i], arguments[i]); + + ExpandedType = decl.Body.Substitute(subst); + } + + private TypeSynonymAnnotation(IToken/*!*/ token, TypeSynonymDecl/*!*/ decl, List/*!*/ arguments, + Type/*!*/ expandedType) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(decl != null); + Contract.Requires(arguments != null); + Contract.Requires(expandedType != null); + + this.Decl = decl; + this.Arguments = arguments; + this.ExpandedType = expandedType; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(varMap)); + } + Type/*!*/ newExpandedType = ExpandedType.Clone(varMap); + Contract.Assert(newExpandedType != null); + return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + return new TypeSynonymAnnotation(tok, Decl, newArgs); + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + //Contract.Requires(that != null); + //Contract.Requires(thisBoundVariables != null); + //Contract.Requires(thatBoundVariables != null); + return ExpandedType.Equals(that, thisBoundVariables, thatBoundVariables); + } + + // used to skip leading type annotations + internal override Type/*!*/ Expanded { + get { + Contract.Ensures(Contract.Result() != null); + + return ExpandedType.Expanded; + } + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + //Contract.Requires(that != null); + //Contract.Requires(unifiableVariables != null); + //Contract.Requires(cce.NonNullElements(result)); + return ExpandedType.Unify(that, unifiableVariables, result); + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + ExpandedType.Unify(that, unifiableVariables, + thisBoundVariables, thatBoundVariables, result); + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (subst.Count == 0) + return this; + List newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Substitute(subst)); + } + Type/*!*/ newExpandedType = ExpandedType.Substitute(subst); + Contract.Assert(newExpandedType != null); + return new TypeSynonymAnnotation(tok, Decl, newArgs, newExpandedType); + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + return ExpandedType.GetHashCode(boundVariables); + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + CtorType.EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + List resolvedArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + resolvedArgs.Add(t.ResolveType(rc)); + } + return new TypeSynonymAnnotation(tok, Decl, resolvedArgs); + } + + public override List/*!*/ FreeVariables { + get { + Contract.Ensures(Contract.Result>() != null); + + return ExpandedType.FreeVariables; + } + } + + public override List/*!*/ FreeProxies { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return ExpandedType.FreeProxies; + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsBasic { + get { + return ExpandedType.IsBasic; + } + } + public override bool IsInt { + get { + return ExpandedType.IsInt; + } + } + public override bool IsReal { + get { + return ExpandedType.IsReal; + } + } + public override bool IsBool { + get { + return ExpandedType.IsBool; + } + } + + public override bool IsVariable { + get { + return ExpandedType.IsVariable; + } + } + public override TypeVariable/*!*/ AsVariable { + get { + Contract.Ensures(Contract.Result() != null); + return ExpandedType.AsVariable; + } + } + public override bool IsCtor { + get { + return ExpandedType.IsCtor; + } + } + public override CtorType/*!*/ AsCtor { + get { + Contract.Ensures(Contract.Result() != null); + return ExpandedType.AsCtor; + } + } + public override bool IsMap { + get { + return ExpandedType.IsMap; + } + } + public override MapType/*!*/ AsMap { + get { + Contract.Ensures(Contract.Result() != null); + return ExpandedType.AsMap; + } + } + public override bool IsUnresolved { + get { + return ExpandedType.IsUnresolved; + } + } + public override UnresolvedTypeIdentifier/*!*/ AsUnresolved { + get { + Contract.Ensures(Contract.Result() != null); + + return ExpandedType.AsUnresolved; + } + } + + public override bool IsBv { + get { + return ExpandedType.IsBv; + } + } + public override int BvBits { + get { + return ExpandedType.BvBits; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitTypeSynonymAnnotation(this); + } + } + + //===================================================================== + + public class CtorType : Type { + public readonly List/*!*/ Arguments; + // is set during resolution and determines whether the right number of arguments is given + public readonly TypeCtorDecl/*!*/ Decl; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Arguments != null); + Contract.Invariant(Decl != null); + } + + + public CtorType(IToken/*!*/ token, TypeCtorDecl/*!*/ decl, List/*!*/ arguments) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(decl != null); + Contract.Requires(arguments != null); + Contract.Requires(arguments.Count == decl.Arity); + this.Decl = decl; + this.Arguments = arguments; + } + + public bool IsDatatype() { + return QKeyValue.FindBoolAttribute(Decl.Attributes, "datatype"); + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(varMap)); + } + return new CtorType(tok, Decl, newArgs); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + return new CtorType(tok, Decl, newArgs); + } + + //----------- Equality ---------------------------------- + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + Type thatType = that as Type; + if (thatType == null) + return false; + thatType = TypeProxy.FollowProxy(thatType.Expanded); + // shortcut + CtorType thatCtorType = thatType as CtorType; + if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) + return false; + if (Arguments.Count == 0) + return true; + return base.Equals(thatType); + } + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) { + that = TypeProxy.FollowProxy(that.Expanded); + CtorType thatCtorType = that as CtorType; + if (thatCtorType == null || !this.Decl.Equals(thatCtorType.Decl)) + return false; + for (int i = 0; i < Arguments.Count; ++i) { + if (!Arguments[i].Equals(thatCtorType.Arguments[i], + thisBoundVariables, thatBoundVariables)) + return false; + } + return true; + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) + return that.Unify(this, unifiableVariables, result); + + CtorType thatCtorType = that as CtorType; + if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) { + return false; + } else { + bool good = true; + for (int i = 0; i < Arguments.Count; ++i) + good &= Arguments[i].Unify(thatCtorType.Arguments[i], unifiableVariables, result); + return good; + } + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + return; + } + + CtorType thatCtorType = that as CtorType; + if (thatCtorType == null || !thatCtorType.Decl.Equals(Decl)) + throw UNIFICATION_FAILED; + for (int i = 0; i < Arguments.Length; ++i) + Arguments[i].Unify(thatCtorType.Arguments[i], + unifiableVariables, + thisBoundVariables, thatBoundVariables, + result); + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (subst.Count == 0) + return this; + List newArgs = new List(); + lock (Arguments) + { + foreach (Type/*!*/ t in Arguments) + { + Contract.Assert(t != null); + newArgs.Add(t.Substitute(subst)); + } + } + return new CtorType(tok, Decl, newArgs); + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + int res = 1637643879 * Decl.GetHashCode(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + res = res * 3 + t.GetHashCode(boundVariables); + } + return res; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + EmitCtorType(this.Decl.Name, Arguments, stream, contextBindingStrength); + } + + internal static void EmitCtorType(string name, List args, TokenTextWriter stream, int contextBindingStrength) { + Contract.Requires(stream != null); + Contract.Requires(args != null); + Contract.Requires(name != null); + int opBindingStrength = args.Count > 0 ? 0 : 2; + if (opBindingStrength < contextBindingStrength) + stream.Write("("); + + stream.Write("{0}", TokenTextWriter.SanitizeIdentifier(name)); + int i = args.Count; + foreach (Type/*!*/ t in args) { + Contract.Assert(t != null); + stream.Write(" "); + // use a lower binding strength for the last argument + // to allow map-types without parentheses + t.Emit(stream, i == 1 ? 1 : 2); + i = i - 1; + } + + if (opBindingStrength < contextBindingStrength) + stream.Write(")"); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + List resolvedArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + resolvedArgs.Add(t.ResolveType(rc)); + } + return new CtorType(tok, Decl, resolvedArgs); + } + + public override List/*!*/ FreeVariables { + get { + List/*!*/ res = new List(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + res.AppendWithoutDups(t.FreeVariables); + } + return res; + } + } + + public override List/*!*/ FreeProxies { + get { + List/*!*/ res = new List(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + AppendWithoutDups(res, t.FreeProxies); + } + return res; + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsCtor { + get { + return true; + } + } + public override CtorType/*!*/ AsCtor { + get { + return this; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitCtorType(this); + } + } + + //===================================================================== + + public class MapType : Type { + // an invariant is that each of the type parameters has to occur as + // free variable in at least one of the arguments + public readonly List/*!*/ TypeParameters; + public readonly List/*!*/ Arguments; + public Type/*!*/ Result; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(TypeParameters != null); + Contract.Invariant(Arguments != null); + Contract.Invariant(Result != null); + } + + + public MapType(IToken/*!*/ token, List/*!*/ typeParameters, List/*!*/ arguments, Type/*!*/ result) + : base(token) { + Contract.Requires(token != null); + Contract.Requires(typeParameters != null); + Contract.Requires(arguments != null); + Contract.Requires(result != null); + + this.TypeParameters = typeParameters; + this.Result = result; + this.Arguments = arguments; + } + + //----------- Cloning ---------------------------------- + // We implement our own clone-method, because bound type variables + // have to be created in the right way. It is /not/ ok to just clone + // everything recursively + + public override Type Clone(IDictionary/*!*/ varMap) { + //Contract.Requires(cce.NonNullElements(varMap)); + Contract.Ensures(Contract.Result() != null); + IDictionary/*!*/ newVarMap = + new Dictionary(); + foreach (KeyValuePair p in varMap) { + Contract.Assert(cce.NonNullElements(p)); + if (!TypeParameters.Contains(p.Key)) + newVarMap.Add(p); + } + + List/*!*/ newTypeParams = new List(); + foreach (TypeVariable/*!*/ var in TypeParameters) { + Contract.Assert(var != null); + TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); + Contract.Assert(newVar != null); + newVarMap.Add(var, newVar); + newTypeParams.Add(newVar); + } + + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.Clone(newVarMap)); + } + Type/*!*/ newResult = Result.Clone(newVarMap); + Contract.Assert(newResult != null); + + return new MapType(this.tok, newTypeParams, newArgs, newResult); + } + + public override Type CloneUnresolved() { + Contract.Ensures(Contract.Result() != null); + List/*!*/ newTypeParams = new List(); + foreach (TypeVariable/*!*/ var in TypeParameters) { + Contract.Assert(var != null); + TypeVariable/*!*/ newVar = new TypeVariable(var.tok, var.Name); + Contract.Assert(newVar != null); + newTypeParams.Add(newVar); + } + + List/*!*/ newArgs = new List(); + foreach (Type/*!*/ t in Arguments) { + Contract.Assert(t != null); + newArgs.Add(t.CloneUnresolved()); + } + Type/*!*/ newResult = Result.CloneUnresolved(); + Contract.Assert(newResult != null); + + return new MapType(this.tok, newTypeParams, newArgs, newResult); + } + + //----------- Equality ---------------------------------- + + [Pure] + public override bool Equals(Type/*!*/ that, + List/*!*/ thisBoundVariables, + List/*!*/ thatBoundVariables) + { + that = TypeProxy.FollowProxy(that.Expanded); + MapType thatMapType = that as MapType; + if (thatMapType == null || + this.TypeParameters.Count != thatMapType.TypeParameters.Count || + this.Arguments.Count != thatMapType.Arguments.Count) + return false; + + thisBoundVariables = thisBoundVariables.ToList(); + foreach (TypeVariable/*!*/ var in this.TypeParameters) + { + Contract.Assert(var != null); + thisBoundVariables.Add(var); + } + thatBoundVariables = thatBoundVariables.ToList(); + foreach (TypeVariable/*!*/ var in thatMapType.TypeParameters) + { + Contract.Assert(var != null); + thatBoundVariables.Add(var); + } + + for (int i = 0; i < Arguments.Count; ++i) + { + if (!Arguments[i].Equals(thatMapType.Arguments[i], + thisBoundVariables, thatBoundVariables)) + return false; + } + + return this.Result.Equals(thatMapType.Result, + thisBoundVariables, thatBoundVariables); + } + + //----------- Unification of types ----------- + + public override bool Unify(Type/*!*/ that, + List/*!*/ unifiableVariables, + IDictionary/*!*/ result) { + that = that.Expanded; + if (that is TypeProxy || that is TypeVariable) + return that.Unify(this, unifiableVariables, result); + + MapType thatMapType = that as MapType; + if (thatMapType == null || + this.TypeParameters.Count != thatMapType.TypeParameters.Count || + this.Arguments.Count != thatMapType.Arguments.Count) + return false; + + // treat the bound variables of the two map types as equal... + Dictionary/*!*/ subst0 = + new Dictionary(); + Dictionary/*!*/ subst1 = + new Dictionary(); + List freshies = new List(); + for (int i = 0; i < this.TypeParameters.Count; i++) { + TypeVariable tp0 = this.TypeParameters[i]; + TypeVariable tp1 = thatMapType.TypeParameters[i]; + TypeVariable freshVar = new TypeVariable(tp0.tok, tp0.Name); + freshies.Add(freshVar); + subst0.Add(tp0, freshVar); + subst1.Add(tp1, freshVar); + } + // ... and then unify the domain and range types + bool good = true; + for (int i = 0; i < this.Arguments.Count; i++) { + Type t0 = this.Arguments[i].Substitute(subst0); + Type t1 = thatMapType.Arguments[i].Substitute(subst1); + good &= t0.Unify(t1, unifiableVariables, result); + } + Type r0 = this.Result.Substitute(subst0); + Type r1 = thatMapType.Result.Substitute(subst1); + good &= r0.Unify(r1, unifiableVariables, result); + + // Finally, check that none of the bound variables has escaped + if (good && freshies.Count != 0) { + // This is done by looking for occurrences of the fresh variables in the + // non-substituted types ... + List freeVars = this.FreeVariables; + foreach (TypeVariable fr in freshies) + if (freeVars.Contains(fr)) { + return false; + } // fresh variable escaped + freeVars = thatMapType.FreeVariables; + foreach (TypeVariable fr in freshies) + if (freeVars.Contains(fr)) { + return false; + } // fresh variable escaped + + // ... and in the resulting unifier of type variables + foreach (KeyValuePair pair in result) { + Contract.Assert(cce.NonNullElements(pair)); + freeVars = pair.Value.FreeVariables; + foreach (TypeVariable fr in freshies) + if (freeVars.Contains(fr)) { + return false; + } // fresh variable escaped + } + } + + return good; + } + +#if OLD_UNIFICATION + public override void Unify(Type! that, + List! unifiableVariables, + List! thisBoundVariables, + List! thatBoundVariables, + IDictionary! result) { + that = that.Expanded; + if (that is TypeVariable) { + that.Unify(this, unifiableVariables, thatBoundVariables, thisBoundVariables, result); + return; + } + + MapType thatMapType = that as MapType; + if (thatMapType == null || + this.TypeParameters.Length != thatMapType.TypeParameters.Length || + this.Arguments.Length != thatMapType.Arguments.Length) + throw UNIFICATION_FAILED; + + // ensure that no collisions occur + if (this.collisionsPossible(result)) { + ((MapType)this.Clone()) + .Unify(that, unifiableVariables, + thisBoundVariables, thatBoundVariables, result); + return; + } + if (thatMapType.collisionsPossible(result)) + thatMapType = (MapType)that.Clone(); + + foreach(TypeVariable/*!*/ var in this.TypeParameters){ +Contract.Assert(var != null); + thisBoundVariables.Add(var);} + foreach(TypeVariable/*!*/ var in thatMapType.TypeParameters){ +Contract.Assert(var != null); + thatBoundVariables.Add(var);} + + try { + + for (int i = 0; i < Arguments.Length; ++i) + Arguments[i].Unify(thatMapType.Arguments[i], + unifiableVariables, + thisBoundVariables, thatBoundVariables, + result); + Result.Unify(thatMapType.Result, + unifiableVariables, + thisBoundVariables, thatBoundVariables, + result); + + } finally { + // make sure that the bound variables are removed again + for (int i = 0; i < this.TypeParameters.Length; ++i) { + thisBoundVariables.Remove(); + thatBoundVariables.Remove(); + } + } + } +#endif + + //----------- Substitution of free variables with types not containing bound variables ----------------- + + [Pure] + private bool collisionsPossible(IDictionary/*!*/ subst) { + Contract.Requires(cce.NonNullDictionaryAndValues(subst)); + // PR: could be written more efficiently + return TypeParameters.Any(param => subst.ContainsKey(param) || subst.Values.Any(val => val.FreeVariables.Contains(param))); + } + + public override Type Substitute(IDictionary/*!*/ subst) { + //Contract.Requires(cce.NonNullElements(subst)); + Contract.Ensures(Contract.Result() != null); + if (subst.Count == 0) + return this; + + // there are two cases in which we have to be careful: + // * a variable to be substituted is shadowed by a variable binder + // * a substituted term contains variables that are bound in the + // type (variable capture) + // + // in both cases, we first clone the type to ensure that bound + // variables are fresh + + if (collisionsPossible(subst)) { + MapType/*!*/ newType = (MapType)this.Clone(); + Contract.Assert(newType != null); + Contract.Assert(newType.Equals(this) && !newType.collisionsPossible(subst)); + return newType.Substitute(subst); + } + + List newArgs = new List(); + lock (Arguments) + { + foreach (Type/*!*/ t in Arguments) + { + Contract.Assert(t != null); + newArgs.Add(t.Substitute(subst)); + } + } + Type/*!*/ newResult = Result.Substitute(subst); + Contract.Assert(newResult != null); + + return new MapType(tok, TypeParameters, newArgs, newResult); + } + + //----------- Hashcodes ---------------------------------- + + [Pure] + public override int GetHashCode(List boundVariables) { + //Contract.Requires(boundVariables != null); + int res = 7643761 * TypeParameters.Count + 65121 * Arguments.Count; + + boundVariables = boundVariables.ToList(); + foreach (TypeVariable/*!*/ var in this.TypeParameters) { + Contract.Assert(var != null); + boundVariables.Add(var); + } + + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + res = res * 5 + t.GetHashCode(boundVariables); + } + res = res * 7 + Result.GetHashCode(boundVariables); + + return res; + } + + //----------- Linearisation ---------------------------------- + + public override void Emit(TokenTextWriter stream, int contextBindingStrength) { + //Contract.Requires(stream != null); + stream.SetToken(this); + + const int opBindingStrength = 1; + if (opBindingStrength < contextBindingStrength) + stream.Write("("); + + EmitOptionalTypeParams(stream, TypeParameters); + + stream.Write("["); + Arguments.Emit(stream, ","); // default binding strength of 0 is ok + stream.Write("]"); + Result.Emit(stream); // default binding strength of 0 is ok + + if (opBindingStrength < contextBindingStrength) + stream.Write(")"); + } + + //----------- Resolution ---------------------------------- + + public override Type ResolveType(ResolutionContext rc) { + //Contract.Requires(rc != null); + Contract.Ensures(Contract.Result() != null); + int previousState = rc.TypeBinderState; + try { + foreach (TypeVariable/*!*/ v in TypeParameters) { + Contract.Assert(v != null); + rc.AddTypeBinder(v); + } + + List resolvedArgs = new List(); + foreach (Type/*!*/ ty in Arguments) { + Contract.Assert(ty != null); + resolvedArgs.Add(ty.ResolveType(rc)); + } + + Type resolvedResult = Result.ResolveType(rc); + + CheckBoundVariableOccurrences(TypeParameters, + resolvedArgs, new List { resolvedResult }, + this.tok, "map arguments", + rc); + + // sort the type parameters so that they are bound in the order of occurrence + List/*!*/ sortedTypeParams = SortTypeParams(TypeParameters, resolvedArgs, resolvedResult); + Contract.Assert(sortedTypeParams != null); + return new MapType(tok, sortedTypeParams, resolvedArgs, resolvedResult); + } finally { + rc.TypeBinderState = previousState; + } + } + + public override List/*!*/ FreeVariables { + get { + List/*!*/ res = FreeVariablesIn(Arguments.ToList()); + Contract.Assert(res != null); + res.AppendWithoutDups(Result.FreeVariables); + foreach (TypeVariable/*!*/ v in TypeParameters.ToArray()) { + Contract.Assert(v != null); + res.Remove(v); + } + return res; + } + } + + public override List/*!*/ FreeProxies { + get { + List/*!*/ res = new List(); + foreach (Type/*!*/ t in Arguments.ToArray()) { + Contract.Assert(t != null); + AppendWithoutDups(res, t.FreeProxies); + } + AppendWithoutDups(res, Result.FreeProxies); + return res; + } + } + + //----------- Getters/Issers ---------------------------------- + + public override bool IsMap { + get { + return true; + } + } + public override MapType/*!*/ AsMap { + get { + return this; + } + } + public override int MapArity { + get { + return Arguments.Count; + } + } + + //------------ Match formal argument types of the map + //------------ on concrete types, substitute the result into the + //------------ result type. Null is returned if so many type checking + //------------ errors occur that the situation is hopeless + + public Type CheckArgumentTypes(List/*!*/ actualArgs, + out TypeParamInstantiation/*!*/ tpInstantiation, + IToken/*!*/ typeCheckingSubject, + string/*!*/ opName, + TypecheckingContext/*!*/ tc) { + Contract.Requires(actualArgs != null); + Contract.Requires(typeCheckingSubject != null); + + Contract.Requires(opName != null); + Contract.Requires(tc != null); +Contract.Ensures(Contract.ValueAtReturn(out tpInstantiation) != null); + List/*!*/ actualTypeParams; + List actualResult = + Type.CheckArgumentTypes(TypeParameters, out actualTypeParams, Arguments, actualArgs, + new List { Result }, null, typeCheckingSubject, opName, tc); + if (actualResult == null) { + tpInstantiation = SimpleTypeParamInstantiation.EMPTY; + return null; + } else { + Contract.Assert(actualResult.Count == 1); + tpInstantiation = SimpleTypeParamInstantiation.From(TypeParameters, actualTypeParams); + return actualResult[0]; + } + } + + public override Absy StdDispatch(StandardVisitor visitor) { + //Contract.Requires(visitor != null); + Contract.Ensures(Contract.Result() != null); + return visitor.VisitMapType(this); + } + } + + //--------------------------------------------------------------------- + + public enum SimpleType { + Int, + Real, + Bool + }; + + + //===================================================================== + + // Interface for representing the instantiations of type parameters of + // polymorphic functions or maps. We introduce an own interface for this + // instead of using a simple list or dictionary, because in some cases + // (due to the type proxies for map types) the actual number and instantiation + // of type parameters can only be determined very late. + [ContractClass(typeof(TypeParamInstantiationContracts))] + public interface TypeParamInstantiation { + // return what formal type parameters there are + List/*!*/ FormalTypeParams { + get; + } + // given a formal type parameter, return the actual instantiation + Type/*!*/ this[TypeVariable/*!*/ var] { + get; + } + } + [ContractClassFor(typeof(TypeParamInstantiation))] + public abstract class TypeParamInstantiationContracts : TypeParamInstantiation { + #region TypeParamInstantiation Members + + public List FormalTypeParams { + + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + throw new NotImplementedException(); + } + } + + public Type this[TypeVariable var] { + get { + Contract.Requires(var != null); + Contract.Ensures(Contract.Result() != null); + + throw new NotImplementedException(); + } + } + + #endregion + } + + + public class SimpleTypeParamInstantiation : TypeParamInstantiation { + private readonly List/*!*/ TypeParams; + [ContractInvariantMethod] + void TypeParamsInvariantMethod() { + Contract.Invariant(cce.NonNullElements(TypeParams)); + } + private readonly IDictionary/*!*/ Instantiations; + [ContractInvariantMethod] + void InstantiationsInvariantMethod() { + Contract.Invariant(cce.NonNullDictionaryAndValues(Instantiations)); + } + + public SimpleTypeParamInstantiation(List/*!*/ typeParams, + IDictionary/*!*/ instantiations) { + Contract.Requires(cce.NonNullElements(typeParams)); + Contract.Requires(cce.NonNullDictionaryAndValues(instantiations)); + this.TypeParams = typeParams; + this.Instantiations = instantiations; + } + + public static TypeParamInstantiation/*!*/ From(List typeParams, List/*!*/ actualTypeParams) { + Contract.Requires(cce.NonNullElements(actualTypeParams)); + Contract.Requires(typeParams != null); + Contract.Requires(typeParams.Count == actualTypeParams.Count); + Contract.Ensures(Contract.Result() != null); + + if (typeParams.Count == 0) + return EMPTY; + + List/*!*/ typeParamList = new List(); + IDictionary/*!*/ dict = new Dictionary(); + for (int i = 0; i < typeParams.Count; ++i) { + typeParamList.Add(typeParams[i]); + dict.Add(typeParams[i], actualTypeParams[i]); + } + return new SimpleTypeParamInstantiation(typeParamList, dict); + } + + public static readonly TypeParamInstantiation EMPTY = + new SimpleTypeParamInstantiation(new List(), + new Dictionary()); + + // return what formal type parameters there are + public List/*!*/ FormalTypeParams { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + return TypeParams; + } + } + // given a formal type parameter, return the actual instantiation + public Type/*!*/ this[TypeVariable/*!*/ var] { + get { + return Instantiations[var]; + } + } + } + + // Implementation of TypeParamInstantiation that refers to the current + // value of a MapTypeProxy. This means that the values return by the + // methods of this implementation can change in case the MapTypeProxy + // receives further unifications. + class MapTypeProxyParamInstantiation : TypeParamInstantiation { + private readonly MapTypeProxy/*!*/ Proxy; + + // the argument and result type of this particular usage of the map + // type. these are necessary to derive the values of the type parameters + private readonly List/*!*/ ArgumentsResult; + + // field that is initialised once all necessary information is available + // (the MapTypeProxy is instantiated to an actual type) and the instantiation + // of a type parameter is queried + private IDictionary Instantiations = null; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Proxy != null); + Contract.Invariant(ArgumentsResult != null); + Contract.Invariant(Instantiations == null || cce.NonNullDictionaryAndValues(Instantiations)); + } + + + public MapTypeProxyParamInstantiation(MapTypeProxy/*!*/ proxy, + List/*!*/ argumentsResult) { + Contract.Requires(proxy != null); + Contract.Requires(argumentsResult != null); + this.Proxy = proxy; + this.ArgumentsResult = argumentsResult; + } + + // return what formal type parameters there are + public List/*!*/ FormalTypeParams { + get { + MapType realType = Proxy.ProxyFor as MapType; + if (realType == null) + // no instantiation of the map type is known, which means + // that the map type is assumed to be monomorphic + return new List(); + else + return realType.TypeParameters.ToList(); + } + } + + // given a formal type parameter, return the actual instantiation + public Type/*!*/ this[TypeVariable/*!*/ var] { + get { + // then there has to be an instantiation that is a polymorphic map type + if (Instantiations == null) { + MapType realType = Proxy.ProxyFor as MapType; + Contract.Assert(realType != null); + List/*!*/ formalArgs = new List(); + foreach (Type/*!*/ t in realType.Arguments) { + Contract.Assert(t != null); + formalArgs.Add(t); + } + formalArgs.Add(realType.Result); + Instantiations = + Type.InferTypeParameters(realType.TypeParameters, formalArgs, ArgumentsResult); + } + return Instantiations[var]; + } + } + } } \ No newline at end of file diff --git a/Source/Core/AlphaEquality.cs b/Source/Core/AlphaEquality.cs index 1d4a1d95..986cc4bd 100644 --- a/Source/Core/AlphaEquality.cs +++ b/Source/Core/AlphaEquality.cs @@ -1,162 +1,162 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System.ComponentModel; - -namespace Microsoft.Boogie -{ - - using System; - using System.IO; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.Contracts; - - public class AlphaEquality : IEqualityComparer - { - private readonly DeBruijnRenamer deBruijn = new DeBruijnRenamer(); - - bool IEqualityComparer.Equals(Expr x, Expr y) { - var nx = deBruijn.Rename(x); - var ny = deBruijn.Rename(y); - return BinderExpr.EqualWithAttributesAndTriggers(nx, ny); - } - - int IEqualityComparer.GetHashCode(Expr obj) { - return 0; - // Best we can do because GetHashCode for Expression don't respect its equality. - // When it does, we can instead use: - // return deBruijn.Rename(obj).GetHashCode(); - } - - // Renames expressions into deBruijn indicies, such as - // (lambda x : int :: x + a) - // into - // (lambda bv#0 : int :: bv#0 + fv#0) - // It does not handle type variables yet, but it could be added. - // - // This class could be made public, but it is not since the Rename method - // could then leak FreeVariables out of here. - private class DeBruijnRenamer : Duplicator - { - - // Maps from index positions and types to new variables - private readonly TypeDict boundVars = - new TypeDict("bv", ti => new BoundVariable(Token.NoToken, ti)); - - private readonly TypeDict freeVars = - new TypeDict("fv", ti => new FreeVariable(ti)); - - // These three variables are reset at the beginning of every renaming - private int boundVarCount, freeVarCount; - private Dictionary freeVarMap; - - // Cached, previous results - private readonly Dictionary cache = new Dictionary(); - - public Expr Rename(Expr e) { - Expr ne; - if (!cache.TryGetValue(e, out ne)) { - boundVarCount = 0; - freeVarCount = 0; - freeVarMap = new Dictionary(); - - ne = VisitExpr(e); - cache[e] = ne; -#if DEBUG_ALPHA_RENAMING - var wr = new TokenTextWriter("", Console.Out, true); - Console.Write("nm( "); - e.Emit(wr); - Console.WriteLine(" )"); - Console.Write(" = "); - ne.Emit(wr); - Console.WriteLine(""); - Console.WriteLine("h = " + ne.GetHashCode()); -#endif - } - return ne; - } - - public override BinderExpr VisitBinderExpr(BinderExpr node) { - var subst = new Dictionary(); - var newBound = new List(); - foreach (var bv in node.Dummies) { - var bvNew = boundVars[boundVarCount++, bv.TypedIdent.Type]; - newBound.Add(bvNew); - subst[bv] = new IdentifierExpr(Token.NoToken, bvNew); - } - node.Dummies = this.VisitVariableSeq(newBound); - node.Body = this.VisitExpr(Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), node.Body)); - return node; - } - - public override Variable VisitVariable(Variable node) { - FreeVariable fv; - var bv = node as BoundVariable; - if (boundVars.ContainsValue(bv)) { - return node; - } else if (freeVarMap.TryGetValue(node, out fv)) { - return fv; - } else { - return freeVarMap[node] = freeVars[freeVarCount++, node.TypedIdent.Type]; - } - } - - public override Expr VisitIdentifierExpr(IdentifierExpr node) { - var ie = (IdentifierExpr) base.VisitIdentifierExpr(node); - // Need to fix up the name, since IdentifierExpr's equality also checks the name - ie.Name = ie.Decl.TypedIdent.Name; - return ie; - } - - private class TypeDict - { - private readonly Dictionary, A> vars = new Dictionary, A>(); - - private readonly string Prefix; // either "bv" or "fv" - private readonly Func Mk; // either new BoundVar or new FreeVar - - public TypeDict(string prefix, Func mk) { - Prefix = prefix; - Mk = mk; - } - - // For debugging purposes, we create unique names when types differ, but the index are the same. - private int created = 0; - - // Make sure that this index and this type is always mapped to the same variable - public A this[int i, Type t] { - get { - A v; - if (!vars.TryGetValue(Tuple.Create(i, t), out v)) { - v = Mk(new TypedIdent(Token.NoToken, Prefix + i + "#" + created++, t)); - vars[Tuple.Create(i, t)] = v; - } - return v; - } - } - - public bool ContainsValue(A a) { - return vars.ContainsValue(a); - } - } - - private class FreeVariable : Variable - { - public FreeVariable(TypedIdent ti) : base(Token.NoToken, ti) {} - - public override bool IsMutable { - get { throw new cce.UnreachableException(); } - } - - public override void Register(ResolutionContext rc) { - throw new cce.UnreachableException(); - } - } - } - } -} +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System.ComponentModel; + +namespace Microsoft.Boogie +{ + + using System; + using System.IO; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.Contracts; + + public class AlphaEquality : IEqualityComparer + { + private readonly DeBruijnRenamer deBruijn = new DeBruijnRenamer(); + + bool IEqualityComparer.Equals(Expr x, Expr y) { + var nx = deBruijn.Rename(x); + var ny = deBruijn.Rename(y); + return BinderExpr.EqualWithAttributesAndTriggers(nx, ny); + } + + int IEqualityComparer.GetHashCode(Expr obj) { + return 0; + // Best we can do because GetHashCode for Expression don't respect its equality. + // When it does, we can instead use: + // return deBruijn.Rename(obj).GetHashCode(); + } + + // Renames expressions into deBruijn indicies, such as + // (lambda x : int :: x + a) + // into + // (lambda bv#0 : int :: bv#0 + fv#0) + // It does not handle type variables yet, but it could be added. + // + // This class could be made public, but it is not since the Rename method + // could then leak FreeVariables out of here. + private class DeBruijnRenamer : Duplicator + { + + // Maps from index positions and types to new variables + private readonly TypeDict boundVars = + new TypeDict("bv", ti => new BoundVariable(Token.NoToken, ti)); + + private readonly TypeDict freeVars = + new TypeDict("fv", ti => new FreeVariable(ti)); + + // These three variables are reset at the beginning of every renaming + private int boundVarCount, freeVarCount; + private Dictionary freeVarMap; + + // Cached, previous results + private readonly Dictionary cache = new Dictionary(); + + public Expr Rename(Expr e) { + Expr ne; + if (!cache.TryGetValue(e, out ne)) { + boundVarCount = 0; + freeVarCount = 0; + freeVarMap = new Dictionary(); + + ne = VisitExpr(e); + cache[e] = ne; +#if DEBUG_ALPHA_RENAMING + var wr = new TokenTextWriter("", Console.Out, true); + Console.Write("nm( "); + e.Emit(wr); + Console.WriteLine(" )"); + Console.Write(" = "); + ne.Emit(wr); + Console.WriteLine(""); + Console.WriteLine("h = " + ne.GetHashCode()); +#endif + } + return ne; + } + + public override BinderExpr VisitBinderExpr(BinderExpr node) { + var subst = new Dictionary(); + var newBound = new List(); + foreach (var bv in node.Dummies) { + var bvNew = boundVars[boundVarCount++, bv.TypedIdent.Type]; + newBound.Add(bvNew); + subst[bv] = new IdentifierExpr(Token.NoToken, bvNew); + } + node.Dummies = this.VisitVariableSeq(newBound); + node.Body = this.VisitExpr(Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), node.Body)); + return node; + } + + public override Variable VisitVariable(Variable node) { + FreeVariable fv; + var bv = node as BoundVariable; + if (boundVars.ContainsValue(bv)) { + return node; + } else if (freeVarMap.TryGetValue(node, out fv)) { + return fv; + } else { + return freeVarMap[node] = freeVars[freeVarCount++, node.TypedIdent.Type]; + } + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) { + var ie = (IdentifierExpr) base.VisitIdentifierExpr(node); + // Need to fix up the name, since IdentifierExpr's equality also checks the name + ie.Name = ie.Decl.TypedIdent.Name; + return ie; + } + + private class TypeDict + { + private readonly Dictionary, A> vars = new Dictionary, A>(); + + private readonly string Prefix; // either "bv" or "fv" + private readonly Func Mk; // either new BoundVar or new FreeVar + + public TypeDict(string prefix, Func mk) { + Prefix = prefix; + Mk = mk; + } + + // For debugging purposes, we create unique names when types differ, but the index are the same. + private int created = 0; + + // Make sure that this index and this type is always mapped to the same variable + public A this[int i, Type t] { + get { + A v; + if (!vars.TryGetValue(Tuple.Create(i, t), out v)) { + v = Mk(new TypedIdent(Token.NoToken, Prefix + i + "#" + created++, t)); + vars[Tuple.Create(i, t)] = v; + } + return v; + } + } + + public bool ContainsValue(A a) { + return vars.ContainsValue(a); + } + } + + private class FreeVariable : Variable + { + public FreeVariable(TypedIdent ti) : base(Token.NoToken, ti) {} + + public override bool IsMutable { + get { throw new cce.UnreachableException(); } + } + + public override void Register(ResolutionContext rc) { + throw new cce.UnreachableException(); + } + } + } + } +} diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg index 644a5d3d..091ceeb0 100644 --- a/Source/Core/BoogiePL.atg +++ b/Source/Core/BoogiePL.atg @@ -1,1511 +1,1511 @@ - -/*--------------------------------------------------------------------------- -// BoogiePL - -//--------------------------------------------------------------------------*/ - -/*using System;*/ -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Microsoft.Boogie; -using Microsoft.Basetypes; -using Bpl = Microsoft.Boogie; - - -COMPILER BoogiePL - -/*--------------------------------------------------------------------------*/ - -readonly Program/*!*/ Pgm; - -readonly Expr/*!*/ dummyExpr; -readonly Cmd/*!*/ dummyCmd; -readonly Block/*!*/ dummyBlock; -readonly Bpl.Type/*!*/ dummyType; -readonly List/*!*/ dummyExprSeq; -readonly TransferCmd/*!*/ dummyTransferCmd; -readonly StructuredCmd/*!*/ dummyStructuredCmd; - -/// -///Returns the number of parsing errors encountered. If 0, "program" returns as -///the parsed program. -/// -public static int Parse (string/*!*/ filename, /*maybe null*/ List defines, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { - Contract.Requires(filename != null); - Contract.Requires(cce.NonNullElements(defines,true)); - - if (defines == null) { - defines = new List(); - } - - if (filename == "stdin.bpl") { - var s = ParserHelper.Fill(Console.In, defines); - return Parse(s, filename, out program, useBaseName); - } else { - FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); - var s = ParserHelper.Fill(stream, defines); - var ret = Parse(s, filename, out program, useBaseName); - stream.Close(); - return ret; - } -} - - -public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { - Contract.Requires(s != null); - Contract.Requires(filename != null); - - byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s)); - MemoryStream ms = new MemoryStream(buffer,false); - Errors errors = new Errors(); - Scanner scanner = new Scanner(ms, errors, filename, useBaseName); - - Parser parser = new Parser(scanner, errors, false); - parser.Parse(); - if (parser.errors.count == 0) - { - program = parser.Pgm; - program.ProcessDatatypeConstructors(); - return 0; - } - else - { - program = null; - return parser.errors.count; - } -} - -public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation) - : this(scanner, errors) -{ - // initialize readonly fields - Pgm = new Program(); - dummyExpr = new LiteralExpr(Token.NoToken, false); - dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr); - dummyBlock = new Block(Token.NoToken, "dummyBlock", new List(), new ReturnCmd(Token.NoToken)); - dummyType = new BasicType(Token.NoToken, SimpleType.Bool); - dummyExprSeq = new List (); - dummyTransferCmd = new ReturnCmd(Token.NoToken); - dummyStructuredCmd = new BreakCmd(Token.NoToken, null); -} - -// Class to represent the bounds of a bitvector expression t[a:b]. -// Objects of this class only exist during parsing and are directly -// turned into BvExtract before they get anywhere else -private class BvBounds : Expr { - public BigNum Lower; - public BigNum Upper; - public BvBounds(IToken/*!*/ tok, BigNum lower, BigNum upper) - : base(tok) { - Contract.Requires(tok != null); - this.Lower = lower; - this.Upper = upper; - } - public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result() != null); return Bpl.Type.Int; } } - public override void Resolve(ResolutionContext/*!*/ rc) { - // Contract.Requires(rc != null); - rc.Error(this, "bitvector bounds in illegal position"); - } - public override void Emit(TokenTextWriter/*!*/ stream, - int contextBindingStrength, bool fragileContext) { - Contract.Assert(false);throw new cce.UnreachableException(); - } - public override void ComputeFreeVariables(GSet/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); } -} - -/*--------------------------------------------------------------------------*/ -CHARACTERS - letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". - digit = "0123456789". - special = "'~#$^_.?`". - glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". - - cr = '\r'. - lf = '\n'. - tab = '\t'. - - space = ' '. - quote = '"'. - - newLine = cr + lf. - regularStringChar = ANY - quote - newLine. - - nondigit = letter + special. - nonquote = letter + digit + space + glyph. - - -/*------------------------------------------------------------------------*/ -TOKENS - ident = [ '\\' ] nondigit {nondigit | digit}. - bvlit = digit {digit} 'b' 'v' digit {digit}. - digits = digit {digit}. - - string = quote { regularStringChar | "\\\"" } quote. - - decimal = digit {digit} 'e' [ '-' ] digit {digit} . - float = digit {digit} '.' digit {digit} [ 'e' [ '-' ] digit {digit} ] . - -COMMENTS FROM "/*" TO "*/" NESTED -COMMENTS FROM "//" TO lf - -IGNORE cr + lf + tab - - -/*------------------------------------------------------------------------*/ -PRODUCTIONS - - -/*------------------------------------------------------------------------*/ -BoogiePL -= (. List/*!*/ vs; - List/*!*/ ds; - Axiom/*!*/ ax; - List/*!*/ ts; - Procedure/*!*/ pr; - Implementation im; - Implementation/*!*/ nnim; - .) - { Consts (. foreach(Bpl.Variable/*!*/ v in vs){ - Contract.Assert(v != null); - Pgm.AddTopLevelDeclaration(v); - } - .) - | Function (. foreach(Bpl.Declaration/*!*/ d in ds){ - Contract.Assert(d != null); - Pgm.AddTopLevelDeclaration(d); - } - .) - | Axiom (. Pgm.AddTopLevelDeclaration(ax); .) - | UserDefinedTypes (. foreach(Declaration/*!*/ td in ts){ - Contract.Assert(td != null); - Pgm.AddTopLevelDeclaration(td); - } - .) - | GlobalVars (. foreach(Bpl.Variable/*!*/ v in vs){ - Contract.Assert(v != null); - Pgm.AddTopLevelDeclaration(v); - } - .) - | Procedure (. Pgm.AddTopLevelDeclaration(pr); - if (im != null) { - Pgm.AddTopLevelDeclaration(im); - } - .) - | Implementation (. Pgm.AddTopLevelDeclaration(nnim); .) - } - EOF - . - -/*------------------------------------------------------------------------*/ -GlobalVars<.out List/*!*/ ds.> -= (. - Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - QKeyValue kv = null; - ds = new List(); - var dsx = ds; - .) - "var" - { Attribute } - IdsTypeWheres ";" - . - -LocalVars<.List/*!*/ ds.> -= (. - Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - QKeyValue kv = null; - .) - "var" - { Attribute } - IdsTypeWheres ";" - . - -ProcFormals<.bool incoming, bool allowWhereClauses, out List/*!*/ ds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - ds = new List(); - var dsx = ds; - var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals"; - .) - "(" - [ AttrsIdsTypeWheres - ] - ")" - . - -BoundVars<.IToken/*!*/ x, out List/*!*/ ds.> -= (. - Contract.Requires(x != null); - Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - List/*!*/ tyds = new List(); - ds = new List(); - var dsx = ds; - .) - AttrsIdsTypeWheres - . - -/*------------------------------------------------------------------------*/ -/* IdsType is used with const declarations */ -IdsType<.out List/*!*/ tyds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List/*!*/ ids; Bpl.Type/*!*/ ty; .) - Idents ":" Type - (. tyds = new List(); - foreach(Token/*!*/ id in ids){ - Contract.Assert(id != null); - tyds.Add(new TypedIdent(id, id.val, ty, null)); - } - .) - . - -/* AttrsIdsTypeWheres is used with the declarations of formals and bound variables */ -AttrsIdsTypeWheres<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> -= - AttributesIdsTypeWhere - { "," AttributesIdsTypeWhere } - . - -IdsTypeWheres<. bool allowWhereClauses, string context, System.Action action .> -= - IdsTypeWhere - { "," IdsTypeWhere } - . - -AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> -= (. QKeyValue kv = null; .) - { Attribute (. if (!allowAttributes) { - kv = null; - this.SemErr("attributes are not allowed on " + context); - } - .) - } - IdsTypeWhere - . - -/* context is allowed to be null if allowWhereClauses is true */ -IdsTypeWhere<. bool allowWhereClauses, string context, System.Action action .> -= (. List/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .) - Idents ":" Type - [ "where" Expression (. if (!allowWhereClauses) { - this.SemErr("where clause not allowed on " + context); - } else { - wh = nne; - } - .) - ] - (. foreach(Token/*!*/ id in ids){ - Contract.Assert(id != null); - action(new TypedIdent(id, id.val, ty, wh)); - } - .) - . - -/*------------------------------------------------------------------------*/ -Type -= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .) - ( - TypeAtom - | - Ident (. List/*!*/ args = new List (); .) - [ TypeArgs ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .) - | - MapType - ) - . - -TypeArgs<.List/*!*/ ts.> -= (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .) - ( - TypeAtom (. ts.Add(ty); .) - [ TypeArgs ] - | - Ident (. List/*!*/ args = new List (); - ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .) - [ TypeArgs ] - | - MapType (. ts.Add(ty); .) - ) - . - -TypeAtom -= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType; .) - ( "int" (. ty = new BasicType(t, SimpleType.Int); .) - | "real" (. ty = new BasicType(t, SimpleType.Real); .) - | "bool" (. ty = new BasicType(t, SimpleType.Bool); .) - /* note: bitvectors are handled in UnresolvedTypeIdentifier */ - | - "(" - Type - ")" - ) - . - -MapType -= (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null; - IToken/*!*/ nnTok; - List/*!*/ arguments = new List(); - Bpl.Type/*!*/ result; - List/*!*/ typeParameters = new List(); - .) - [ TypeParams (. tok = nnTok; .) ] - "[" (. if (tok == null) tok = t; .) - [ Types ] - "]" - Type - (. - ty = new MapType(tok, typeParameters, arguments, result); - .) - . - -TypeParams<.out IToken/*!*/ tok, out List/*!*/ typeParams.> -= (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List/*!*/ typeParamToks; .) - "<" (. tok = t; .) - Idents - ">" - (. - typeParams = new List (); - foreach(Token/*!*/ id in typeParamToks){ - Contract.Assert(id != null); - typeParams.Add(new TypeVariable(id, id.val));} - .) - . - -Types<.List/*!*/ ts.> -= (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .) - Type (. ts.Add(ty); .) - { "," Type (. ts.Add(ty); .) - } - . - - -/*------------------------------------------------------------------------*/ -Consts<.out List/*!*/ ds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List/*!*/ xs; - ds = new List(); - bool u = false; QKeyValue kv = null; - bool ChildrenComplete = false; - List Parents = null; .) - "const" (. y = t; .) - { Attribute } - [ "unique" (. u = true; .) - ] - IdsType - [ OrderSpec ] - (. bool makeClone = false; - foreach(TypedIdent/*!*/ x in xs){ - Contract.Assert(x != null); - - // ensure that no sharing is introduced - List ParentsClone; - if (makeClone && Parents != null) { - ParentsClone = new List (); - foreach (ConstantParent/*!*/ p in Parents){ - Contract.Assert(p != null); - ParentsClone.Add(new ConstantParent ( - new IdentifierExpr (p.Parent.tok, p.Parent.Name), - p.Unique));} - } else { - ParentsClone = Parents; - } - makeClone = true; - - ds.Add(new Constant(y, x, u, ParentsClone, ChildrenComplete, kv)); - } - .) - ";" - . - -OrderSpec<.out bool ChildrenComplete, out List Parents.> -= (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false; - Parents = null; - bool u; - IToken/*!*/ parent; .) - "extends" (. Parents = new List (); - u = false; .) - [ - [ "unique" (. u = true; .) - ] - Ident (. Parents.Add(new ConstantParent ( - new IdentifierExpr(parent, parent.val), u)); .) - { - "," (. u = false; .) - [ "unique" (. u = true; .) - ] - Ident (. Parents.Add(new ConstantParent ( - new IdentifierExpr(parent, parent.val), u)); .) - } - ] - [ "complete" (. ChildrenComplete = true; .) - ] - . - -/*------------------------------------------------------------------------*/ -Function<.out List/*!*/ ds.> -= (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); - ds = new List(); IToken/*!*/ z; - IToken/*!*/ typeParamTok; - var typeParams = new List(); - var arguments = new List(); - TypedIdent/*!*/ tyd; - TypedIdent retTyd = null; - Bpl.Type/*!*/ retTy; - QKeyValue argKv = null; - QKeyValue kv = null; - Expr definition = null; - Expr/*!*/ tmp; - .) - "function" { Attribute } Ident - [ TypeParams ] - "(" - [ VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) - { "," VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) - } ] ")" - (. argKv = null; .) - ( - "returns" "(" VarOrType ")" - | - ":" Type (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .) - ) - ( "{" Expression (. definition = tmp; .) "}" | ";" ) - (. - if (retTyd == null) { - // construct a dummy type for the case of syntax error - retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); - } - Function/*!*/ func = new Function(z, z.val, typeParams, arguments, - new Formal(retTyd.tok, retTyd, false, argKv), null, kv); - Contract.Assert(func != null); - ds.Add(func); - bool allUnnamed = true; - foreach(Formal/*!*/ f in arguments){ - Contract.Assert(f != null); - if (f.TypedIdent.HasName) { - allUnnamed = false; - break; - } - } - if (!allUnnamed) { - Bpl.Type prevType = null; - for (int i = arguments.Count; 0 <= --i; ) { - TypedIdent/*!*/ curr = cce.NonNull(arguments[i]).TypedIdent; - if (curr.HasName) { - // the argument was given as both an identifier and a type - prevType = curr.Type; - } else { - // the argument was given as just one "thing", which syntactically parsed as a type - if (prevType == null) { - this.errors.SemErr(curr.tok, "the type of the last parameter is unspecified"); - break; - } - Bpl.Type ty = curr.Type; - var uti = ty as UnresolvedTypeIdentifier; - if (uti != null && uti.Arguments.Count == 0) { - // the given "thing" was just an identifier, so let's use it as the name of the parameter - curr.Name = uti.Name; - curr.Type = prevType; - } else { - this.errors.SemErr(curr.tok, "expecting an identifier as parameter name"); - } - } - } - } - if (definition != null) { - // generate either an axiom or a function body - if (QKeyValue.FindBoolAttribute(kv, "inline")) { - func.Body = definition; - } else { - ds.Add(func.CreateDefinitionAxiom(definition, kv)); - } - } - .) - . - -VarOrType -= (. - Contract.Ensures(Contract.ValueAtReturn(out tyd) != null); - string/*!*/ varName = TypedIdent.NoName; - Bpl.Type/*!*/ ty; - IToken/*!*/ tok; - kv = null; - .) - { Attribute } - Type (. tok = ty.tok; .) - [ ":" (. var uti = ty as UnresolvedTypeIdentifier; - if (uti != null && uti.Arguments.Count == 0) { - varName = uti.Name; - } else { - this.SemErr("expected identifier before ':'"); - } - .) - Type - ] - (. tyd = new TypedIdent(tok, varName, ty); .) - . - -/*------------------------------------------------------------------------*/ -Axiom -= (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .) - "axiom" - { Attribute } - (. IToken/*!*/ x = t; .) - Proposition ";" (. m = new Axiom(x,e, null, kv); .) - . - -/*------------------------------------------------------------------------*/ -UserDefinedTypes<.out List/*!*/ ts.> -= (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List (); .) - "type" - { Attribute } - UserDefinedType (. ts.Add(decl); .) - { "," UserDefinedType (. ts.Add(decl); .) } - ";" - . - -UserDefinedType -= (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List/*!*/ paramTokens = new List (); - Bpl.Type/*!*/ body = dummyType; bool synonym = false; .) - Ident - [ WhiteSpaceIdents ] - [ - "=" Type - (. synonym = true; .) - ] - (. - if (synonym) { - List/*!*/ typeParams = new List(); - foreach(Token/*!*/ t in paramTokens){ - Contract.Assert(t != null); - typeParams.Add(new TypeVariable(t, t.val));} - decl = new TypeSynonymDecl(id, id.val, typeParams, body, kv); - } else { - decl = new TypeCtorDecl(id, id.val, paramTokens.Count, kv); - } - .) - . - - -/*------------------------------------------------------------------------*/ -Procedure -= (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x; - List/*!*/ typeParams; - List/*!*/ ins, outs; - List/*!*/ pre = new List(); - List/*!*/ mods = new List(); - List/*!*/ post = new List(); - - List/*!*/ locals = new List(); - StmtList/*!*/ stmtList; - QKeyValue kv = null; - impl = null; - .) - - "procedure" - ProcSignature - ( ";" - { Spec } - | { Spec } - ImplBody - (. - impl = new Implementation(x, x.val, typeParams, - Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); - .) - ) - (. proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); .) - . - - -Implementation -= (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x; - List/*!*/ typeParams; - List/*!*/ ins, outs; - List/*!*/ locals; - StmtList/*!*/ stmtList; - QKeyValue kv; - .) - - "implementation" - ProcSignature - ImplBody - (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .) - . - - -ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List/*!*/ typeParams, - out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv.> -= (. Contract.Ensures(Contract.ValueAtReturn(out name) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ins) != null); Contract.Ensures(Contract.ValueAtReturn(out outs) != null); - IToken/*!*/ typeParamTok; typeParams = new List(); - outs = new List(); kv = null; .) - { Attribute } - Ident - [ TypeParams ] - ProcFormals - [ "returns" ProcFormals ] - . - - -Spec<.List/*!*/ pre, List/*!*/ mods, List/*!*/ post.> -= (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List/*!*/ ms; .) - ( "modifies" - [ Idents (. foreach(IToken/*!*/ m in ms){ - Contract.Assert(m != null); - mods.Add(new IdentifierExpr(m, m.val)); - } - .) - ] ";" - | "free" SpecPrePost - | SpecPrePost - ) - . - -SpecPrePost<.bool free, List/*!*/ pre, List/*!*/ post.> -= (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .) - ( "requires" (. tok = t; .) - { Attribute } - Proposition ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .) - | "ensures" (. tok = t; .) - { Attribute } - Proposition ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .) - ) - . - -/*------------------------------------------------------------------------*/ - -ImplBody<.out List/*!*/ locals, out StmtList/*!*/ stmtList.> -= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List(); .) - "{" - { LocalVars } - StmtList - . - -/* the StmtList also reads the final curly brace */ -StmtList -= (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List bigblocks = new List(); - /* built-up state for the current BigBlock: */ - IToken startToken = null; string currentLabel = null; - List cs = null; /* invariant: startToken != null ==> cs != null */ - /* temporary variables: */ - IToken label; Cmd c; BigBlock b; - StructuredCmd ec = null; StructuredCmd/*!*/ ecn; - TransferCmd tc = null; TransferCmd/*!*/ tcn; - .) - - { - ( LabelOrCmd - (. if (c != null) { - // LabelOrCmd read a Cmd - Contract.Assert(label == null); - if (startToken == null) { startToken = c.tok; cs = new List(); } - Contract.Assert(cs != null); - cs.Add(c); - } else { - // LabelOrCmd read a label - Contract.Assert(label != null); - if (startToken != null) { - Contract.Assert(cs != null); - // dump the built-up state into a BigBlock - b = new BigBlock(startToken, currentLabel, cs, null, null); - bigblocks.Add(b); - cs = null; - } - startToken = label; - currentLabel = label.val; - cs = new List(); - } - .) - - | StructuredCmd - (. ec = ecn; - if (startToken == null) { startToken = ec.tok; cs = new List(); } - Contract.Assert(cs != null); - b = new BigBlock(startToken, currentLabel, cs, ec, null); - bigblocks.Add(b); - startToken = null; currentLabel = null; cs = null; - .) - - | TransferCmd - (. tc = tcn; - if (startToken == null) { startToken = tc.tok; cs = new List(); } - Contract.Assert(cs != null); - b = new BigBlock(startToken, currentLabel, cs, null, tc); - bigblocks.Add(b); - startToken = null; currentLabel = null; cs = null; - .) - - ) - } - "}" - (. IToken/*!*/ endCurly = t; - if (startToken == null && bigblocks.Count == 0) { - startToken = t; cs = new List(); - } - if (startToken != null) { - Contract.Assert(cs != null); - b = new BigBlock(startToken, currentLabel, cs, null, null); - bigblocks.Add(b); - } - - stmtList = new StmtList(bigblocks, endCurly); - .) - . - -TransferCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd; - Token y; List/*!*/ xs; - List ss = new List(); - .) - ( "goto" (. y = t; .) - Idents (. foreach(IToken/*!*/ s in xs){ - Contract.Assert(s != null); - ss.Add(s.val); } - tc = new GotoCmd(y, ss); - .) - | "return" (. tc = new ReturnCmd(t); .) - ) ";" - . - -StructuredCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec)); - IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd; - .) - ( IfCmd (. ec = ifcmd; .) - | WhileCmd (. ec = wcmd; .) - | BreakCmd (. ec = bcmd; .) - ) - . - -IfCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x; - Expr guard; - StmtList/*!*/ thn; - IfCmd/*!*/ elseIf; IfCmd elseIfOption = null; - StmtList/*!*/ els; StmtList elseOption = null; - .) - "if" (. x = t; .) - Guard - "{" StmtList - [ "else" - ( IfCmd (. elseIfOption = elseIf; .) - | "{" - StmtList (. elseOption = els; .) - ) - ] - (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .) - . - -WhileCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z; - Expr guard; Expr/*!*/ e; bool isFree; - List invariants = new List(); - StmtList/*!*/ body; - QKeyValue kv = null; - .) - "while" (. x = t; .) - Guard (. Contract.Assume(guard == null || cce.Owner.None(guard)); .) - { (. isFree = false; z = la/*lookahead token*/; .) - [ "free" (. isFree = true; .) - ] - "invariant" - { Attribute } - Expression (. if (isFree) { - invariants.Add(new AssumeCmd(z, e, kv)); - } else { - invariants.Add(new AssertCmd(z, e, kv)); - } - kv = null; - .) - ";" - } - "{" - StmtList (. wcmd = new WhileCmd(x, guard, invariants, body); .) - . - -Guard -= (. Expr/*!*/ ee; e = null; .) - "(" - ( "*" (. e = null; .) - | Expression (. e = ee; .) - ) - ")" - . - -BreakCmd -= (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y; - string breakLabel = null; - .) - "break" (. x = t; .) - [ Ident (. breakLabel = y.val; .) - ] ";" (. bcmd = new BreakCmd(x, breakLabel); .) - . - -/*------------------------------------------------------------------------*/ - -LabelOrCmd -/* ensures (c == null) != (label != null) */ -= (. IToken/*!*/ x; Expr/*!*/ e; - List/*!*/ xs; - List ids; - c = dummyCmd; label = null; - Cmd/*!*/ cn; - QKeyValue kv = null; - .) - ( LabelOrAssign - | "assert" (. x = t; .) - { Attribute } - Proposition (. c = new AssertCmd(x, e, kv); .) - ";" - | "assume" (. x = t; .) - { Attribute } - Proposition (. c = new AssumeCmd(x, e, kv); .) - ";" - | "havoc" (. x = t; .) - Idents ";" (. ids = new List(); - foreach(IToken/*!*/ y in xs){ - Contract.Assert(y != null); - ids.Add(new IdentifierExpr(y, y.val)); - } - c = new HavocCmd(x,ids); - .) - | CallCmd ";" (. c = cn; .) - | ParCallCmd (. c = cn; .) - | "yield" (. x = t; .) - ";" (. c = new YieldCmd(x); .) - ) - . - -/*------------------------------------------------------------------------*/ - -LabelOrAssign -/* ensures (c == null) != (label != null) */ -= (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0; - c = dummyCmd; label = null; - AssignLhs/*!*/ lhs; - List/*!*/ lhss; - List/*!*/ rhss; - List/*!*/ indexes; - .) - Ident (. x = t; .) - ( ":" (. c = null; label = x; .) - - | (. lhss = new List(); .) - (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) - - { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } - (. lhss.Add(lhs); .) - - { "," - Ident - (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) - { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } - (. lhss.Add(lhs); .) - } - - ":=" (. x = t; /* use location of := */ .) - Expression (. rhss = new List (); - rhss.Add(e0); .) - { "," - Expression (. rhss.Add(e0); .) - } - ";" (. c = new AssignCmd(x, lhss, rhss); .) - ) - . - -MapAssignIndex<.out IToken/*!*/ x, out List/*!*/ indexes.> -= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List (); - Expr/*!*/ e; - .) - "[" (. x = t; .) - [ - Expression (. indexes.Add(e); .) - { "," - Expression (. indexes.Add(e); .) - } - ] - "]" - . - -/*------------------------------------------------------------------------*/ -CallCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); - IToken x; - bool isAsync = false; - bool isFree = false; - QKeyValue kv = null; - c = null; - .) - [ "async" (. isAsync = true; .) - ] - [ "free" (. isFree = true; .) - ] - "call" (. x = t; .) - { Attribute } - CallParams (. .) - . - -ParCallCmd -= (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); - IToken x; - QKeyValue kv = null; - Cmd c = null; - List callCmds = new List(); - .) - "par" (. x = t; .) - { Attribute } - CallParams (. callCmds.Add((CallCmd)c); .) - { "|" CallParams (. callCmds.Add((CallCmd)c); .) - } - ";" (. d = new ParCallCmd(x, callCmds, kv); .) - . - -CallParams -= (. - List ids = new List(); - List es = new List(); - Expr en; - IToken first; - IToken p; - c = null; - .) - Ident - ( "(" - [ Expression (. es.Add(en); .) - { "," Expression (. es.Add(en); .) - } - ] - ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) - | - (. ids.Add(new IdentifierExpr(first, first.val)); .) - [ "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) - { "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) - } - ] ":=" - Ident "(" - [ Expression (. es.Add(en); .) - { "," Expression (. es.Add(en); .) - } - ] - ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) - ) - . - -/*------------------------------------------------------------------------*/ -Proposition -=(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.) - Expression - . - -/*------------------------------------------------------------------------*/ -Idents<.out List/*!*/ xs.> -= (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) - Ident (. xs.Add(id); .) - { "," Ident (. xs.Add(id); .) - } - . - -/*------------------------------------------------------------------------*/ -WhiteSpaceIdents<.out List/*!*/ xs.> -= (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) - Ident (. xs.Add(id); .) - { Ident (. xs.Add(id); .) - } - . - -/*------------------------------------------------------------------------*/ -Expressions<.out List/*!*/ es.> -= (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List(); .) - Expression (. es.Add(e); .) - { "," Expression (. es.Add(e); .) - } - . - -/*------------------------------------------------------------------------*/ -Expression<.out Expr/*!*/ e0.> -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - ImpliesExpression - { EquivOp (. x = t; .) - ImpliesExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .) - } - . - -EquivOp = "<==>" | '\u21d4'. - -/*------------------------------------------------------------------------*/ -ImpliesExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - LogicalExpression - [ - ImpliesOp (. x = t; .) - /* recurse because implication is right-associative */ - ImpliesExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1); .) - | - ExpliesOp (. if (noExplies) - this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate"); - x = t; .) - LogicalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) - /* loop because explies is left-associative */ - { - ExpliesOp (. x = t; .) - LogicalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) - } - ] - . - -ImpliesOp = "==>" | '\u21d2'. -ExpliesOp = "<==" | '\u21d0'. - -/*------------------------------------------------------------------------*/ -LogicalExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - RelationalExpression - [ AndOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) - { AndOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) - } - | OrOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) - { OrOp (. x = t; .) - RelationalExpression - (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) - } - ] - . - -AndOp = "&&" | '\u2227'. -OrOp = "||" | '\u2228'. - -/*------------------------------------------------------------------------*/ -RelationalExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) - BvTerm - [ RelOp - BvTerm (. e0 = Expr.Binary(x, op, e0, e1); .) - ] - . - -RelOp -= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) - ( "==" (. x = t; op=BinaryOperator.Opcode.Eq; .) - | "<" (. x = t; op=BinaryOperator.Opcode.Lt; .) - | ">" (. x = t; op=BinaryOperator.Opcode.Gt; .) - | "<=" (. x = t; op=BinaryOperator.Opcode.Le; .) - | ">=" (. x = t; op=BinaryOperator.Opcode.Ge; .) - | "!=" (. x = t; op=BinaryOperator.Opcode.Neq; .) - | "<:" (. x = t; op=BinaryOperator.Opcode.Subtype; .) - | '\u2260' (. x = t; op=BinaryOperator.Opcode.Neq; .) - | '\u2264' (. x = t; op=BinaryOperator.Opcode.Le; .) - | '\u2265' (. x = t; op=BinaryOperator.Opcode.Ge; .) - ) - . - -/*------------------------------------------------------------------------*/ -BvTerm -= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - Term - { "++" (. x = t; .) - Term (. e0 = new BvConcatExpr(x, e0, e1); .) - } - . - - -/*------------------------------------------------------------------------*/ -Term -= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) - Factor - { AddOp - Factor (. e0 = Expr.Binary(x, op, e0, e1); .) - } - . - -AddOp -= (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) - ( "+" (. x = t; op=BinaryOperator.Opcode.Add; .) - | "-" (. x = t; op=BinaryOperator.Opcode.Sub; .) - ) - . - -/*------------------------------------------------------------------------*/ -Factor -= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) - Power - { MulOp - Power (. e0 = Expr.Binary(x, op, e0, e1); .) - } - . - -MulOp -= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) - ( "*" (. x = t; op=BinaryOperator.Opcode.Mul; .) - | "div" (. x = t; op=BinaryOperator.Opcode.Div; .) - | "mod" (. x = t; op=BinaryOperator.Opcode.Mod; .) - | "/" (. x = t; op=BinaryOperator.Opcode.RealDiv; .) - ) - . - -/*------------------------------------------------------------------------*/ -Power -= (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) - UnaryExpression - [ - "**" (. x = t; .) - /* recurse because exponentation is right-associative */ - Power (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .) - ] - . - -/*------------------------------------------------------------------------*/ -UnaryExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; - e = dummyExpr; - .) - ( "-" (. x = t; .) - UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .) - | NegOp (. x = t; .) - UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .) - | CoercionExpression - ) - . - -NegOp = "!" | '\u00ac'. - -/*------------------------------------------------------------------------*/ - -/* This production creates ambiguities, because types can start with "<" - (polymorphic map types), but can also be followed by "<" (inequalities). - Coco deals with these ambiguities in a reasonable way by preferring to read - further types (type arguments) over relational symbols. E.g., "5 : C < 0" - will cause a parse error because "<" is treated as the beginning of a - map type. */ - -CoercionExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; - Bpl.Type/*!*/ coercedTo; - BigNum bn; - .) - ArrayExpression - { ":" (. x = t; .) - ( - Type (. e = Expr.CoerceType(x, e, coercedTo); .) - | - Nat /* This means that we really look at a bitvector - expression t[a:b] */ - (. if (!(e is LiteralExpr) || !((LiteralExpr)e).isBigNum) { - this.SemErr("arguments of extract need to be integer literals"); - e = new BvBounds(x, bn, BigNum.ZERO); - } else { - e = new BvBounds(x, bn, ((LiteralExpr)e).asBigNum); - } - .) - ) - } - . - -/*------------------------------------------------------------------------*/ -ArrayExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; - Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1; - bool store; bool bvExtract; - List/*!*/ allArgs = dummyExprSeq; - .) - AtomExpression - { "[" (. x = t; allArgs = new List (); - allArgs.Add(e); - store = false; bvExtract = false; .) - [ - Expression - (. if (index0 is BvBounds) - bvExtract = true; - else - allArgs.Add(index0); - .) - { "," Expression - (. if (bvExtract || e1 is BvBounds) - this.SemErr("bitvectors only have one dimension"); - allArgs.Add(e1); - .) - } - [ ":=" Expression - (. if (bvExtract || e1 is BvBounds) - this.SemErr("assignment to bitvectors is not possible"); - allArgs.Add(e1); store = true; - .) - ] - | ":=" Expression (. allArgs.Add(e1); store = true; .) - ] - "]" - (. if (store) - e = new NAryExpr(x, new MapStore(x, allArgs.Count - 2), allArgs); - else if (bvExtract) - e = new BvExtractExpr(x, e, - ((BvBounds)index0).Upper.ToIntSafe, - ((BvBounds)index0).Lower.ToIntSafe); - else - e = new NAryExpr(x, new MapSelect(x, allArgs.Count - 1), allArgs); - .) - } - . - - -/*------------------------------------------------------------------------*/ -AtomExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; - List/*!*/ es; List/*!*/ ds; Trigger trig; - List/*!*/ typeParams; - IdentifierExpr/*!*/ id; - QKeyValue kv; - e = dummyExpr; - List/*!*/ locals; - List/*!*/ blocks; - .) - ( "false" (. e = new LiteralExpr(t, false); .) - | "true" (. e = new LiteralExpr(t, true); .) - | Nat (. e = new LiteralExpr(t, bn); .) - | Dec (. e = new LiteralExpr(t, bd); .) - | BvLit (. e = new LiteralExpr(t, bn, n); .) - - | Ident (. id = new IdentifierExpr(x, x.val); e = id; .) - [ "(" - ( Expressions (. e = new NAryExpr(x, new FunctionCall(id), es); .) - | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List()); .) - ) - ")" - ] - - | "old" (. x = t; .) - "(" - Expression - ")" (. e = new OldExpr(x, e); .) - - | "int" (. x = t; .) - "(" - Expression - ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List{ e }); .) - - | "real" (. x = t; .) - "(" - Expression - ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); .) - - | "(" ( Expression (. if (e is BvBounds) - this.SemErr("parentheses around bitvector bounds " + - "are not allowed"); .) - | Forall (. x = t; .) - QuantifierBody - (. if (typeParams.Count + ds.Count > 0) - e = new ForallExpr(x, typeParams, ds, kv, trig, e); .) - | Exists (. x = t; .) - QuantifierBody - (. if (typeParams.Count + ds.Count > 0) - e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .) - | Lambda (. x = t; .) - QuantifierBody - (. if (trig != null) - SemErr("triggers not allowed in lambda expressions"); - if (typeParams.Count + ds.Count > 0) - e = new LambdaExpr(x, typeParams, ds, kv, e); .) - ) - ")" - | IfThenElseExpression - | CodeExpression (. e = new CodeExpr(locals, blocks); .) - ) - . - -CodeExpression<.out List/*!*/ locals, out List/*!*/ blocks.> -= (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List(); Block/*!*/ b; - blocks = new List(); - .) - "|{" - { LocalVars } - SpecBlock (. blocks.Add(b); .) - { SpecBlock (. blocks.Add(b); .) - } - "}|" - . - -SpecBlock -= (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y; - Cmd c; IToken label; - List cs = new List(); - List/*!*/ xs; - List ss = new List(); - b = dummyBlock; - Expr/*!*/ e; - .) - Ident ":" - { LabelOrCmd - (. if (c != null) { - Contract.Assert(label == null); - cs.Add(c); - } else { - Contract.Assert(label != null); - SemErr("SpecBlock's can only have one label"); - } - .) - } - ( "goto" (. y = t; .) - Idents (. foreach(IToken/*!*/ s in xs){ - Contract.Assert(s != null); - ss.Add(s.val); } - b = new Block(x,x.val,cs,new GotoCmd(y,ss)); - .) - | "return" Expression - (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .) - ) - ";" - . - -Attribute -= (. Trigger trig = null; .) - AttributeOrTrigger (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .) -. - -AttributeOrTrigger -= (. IToken/*!*/ tok; Expr/*!*/ e; List/*!*/ es; - string key; - List parameters; object/*!*/ param; - .) - "{" (. tok = t; .) - ( - ":" ident (. key = t.val; parameters = new List(); .) - [ AttributeParameter (. parameters.Add(param); .) - { "," AttributeParameter (. parameters.Add(param); .) - } - ] - (. if (key == "nopats") { - if (parameters.Count == 1 && parameters[0] is Expr) { - e = (Expr)parameters[0]; - if(trig==null){ - trig = new Trigger(tok, false, new List { e }, null); - } else { - trig.AddLast(new Trigger(tok, false, new List { e }, null)); - } - } else { - this.SemErr("the 'nopats' quantifier attribute expects a string-literal parameter"); - } - } else { - if (kv==null) { - kv = new QKeyValue(tok, key, parameters, null); - } else { - kv.AddLast(new QKeyValue(tok, key, parameters, null)); - } - } - .) - | - Expression (. es = new List { e }; .) - { "," Expression (. es.Add(e); .) - } (. if (trig==null) { - trig = new Trigger(tok, true, es, null); - } else { - trig.AddLast(new Trigger(tok, true, es, null)); - } - .) - ) - "}" - . - -AttributeParameter -= (. Contract.Ensures(Contract.ValueAtReturn(out o) != null); - o = "error"; - Expr/*!*/ e; - .) - ( string (. o = t.val.Substring(1, t.val.Length-2); .) - | Expression (. o = e; .) - ) - . - -IfThenElseExpression -= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); - IToken/*!*/ tok; - Expr/*!*/ e0, e1, e2; - e = dummyExpr; .) - "if" (. tok = t; .) Expression "then" Expression "else" Expression - (. e = new NAryExpr(tok, new IfThenElse(tok), new List{ e0, e1, e2 }); .) - . - - -QuantifierBody<.IToken/*!*/ q, out List/*!*/ typeParams, out List/*!*/ ds, - out QKeyValue kv, out Trigger trig, out Expr/*!*/ body.> -= (. Contract.Requires(q != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); Contract.Ensures(Contract.ValueAtReturn(out body) != null); - trig = null; typeParams = new List (); - IToken/*!*/ tok; - kv = null; - ds = new List (); - .) - ( - TypeParams - [ BoundVars ] - | - BoundVars - ) - QSep - { AttributeOrTrigger } - Expression - . - -Forall = "forall" | '\u2200'. -Exists = "exists" | '\u2203'. -Lambda = "lambda" | '\u03bb'. -QSep = "::" | '\u2022'. - -/*------------------------------------------------------------------------*/ -Ident -=(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.) - ident (. x = t; - if (x.val.StartsWith("\\")) - x.val = x.val.Substring(1); - .) - . - -/*------------------------------------------------------------------------*/ -Nat -= - digits - (. try { - n = BigNum.FromString(t.val); - } catch (FormatException) { - this.SemErr("incorrectly formatted number"); - n = BigNum.ZERO; - } - .) - . - -/*------------------------------------------------------------------------*/ -Dec -= (. string s = ""; .) - ( - decimal (. s = t.val; .) - | - float (. s = t.val; .) - ) - (. try { - n = BigDec.FromString(s); - } catch (FormatException) { - this.SemErr("incorrectly formatted number"); - n = BigDec.ZERO; - } - .) - . - -/*------------------------------------------------------------------------*/ -BvLit -= - bvlit - (. - int pos = t.val.IndexOf("bv"); - string a = t.val.Substring(0, pos); - string b = t.val.Substring(pos + 2); - try { - n = BigNum.FromString(a); - m = Convert.ToInt32(b); - } catch (FormatException) { - this.SemErr("incorrectly formatted bitvector"); - n = BigNum.ZERO; - m = 0; - } - .) - . -END BoogiePL. + +/*--------------------------------------------------------------------------- +// BoogiePL - +//--------------------------------------------------------------------------*/ + +/*using System;*/ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.Boogie; +using Microsoft.Basetypes; +using Bpl = Microsoft.Boogie; + + +COMPILER BoogiePL + +/*--------------------------------------------------------------------------*/ + +readonly Program/*!*/ Pgm; + +readonly Expr/*!*/ dummyExpr; +readonly Cmd/*!*/ dummyCmd; +readonly Block/*!*/ dummyBlock; +readonly Bpl.Type/*!*/ dummyType; +readonly List/*!*/ dummyExprSeq; +readonly TransferCmd/*!*/ dummyTransferCmd; +readonly StructuredCmd/*!*/ dummyStructuredCmd; + +/// +///Returns the number of parsing errors encountered. If 0, "program" returns as +///the parsed program. +/// +public static int Parse (string/*!*/ filename, /*maybe null*/ List defines, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { + Contract.Requires(filename != null); + Contract.Requires(cce.NonNullElements(defines,true)); + + if (defines == null) { + defines = new List(); + } + + if (filename == "stdin.bpl") { + var s = ParserHelper.Fill(Console.In, defines); + return Parse(s, filename, out program, useBaseName); + } else { + FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + var s = ParserHelper.Fill(stream, defines); + var ret = Parse(s, filename, out program, useBaseName); + stream.Close(); + return ret; + } +} + + +public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { + Contract.Requires(s != null); + Contract.Requires(filename != null); + + byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s)); + MemoryStream ms = new MemoryStream(buffer,false); + Errors errors = new Errors(); + Scanner scanner = new Scanner(ms, errors, filename, useBaseName); + + Parser parser = new Parser(scanner, errors, false); + parser.Parse(); + if (parser.errors.count == 0) + { + program = parser.Pgm; + program.ProcessDatatypeConstructors(); + return 0; + } + else + { + program = null; + return parser.errors.count; + } +} + +public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation) + : this(scanner, errors) +{ + // initialize readonly fields + Pgm = new Program(); + dummyExpr = new LiteralExpr(Token.NoToken, false); + dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr); + dummyBlock = new Block(Token.NoToken, "dummyBlock", new List(), new ReturnCmd(Token.NoToken)); + dummyType = new BasicType(Token.NoToken, SimpleType.Bool); + dummyExprSeq = new List (); + dummyTransferCmd = new ReturnCmd(Token.NoToken); + dummyStructuredCmd = new BreakCmd(Token.NoToken, null); +} + +// Class to represent the bounds of a bitvector expression t[a:b]. +// Objects of this class only exist during parsing and are directly +// turned into BvExtract before they get anywhere else +private class BvBounds : Expr { + public BigNum Lower; + public BigNum Upper; + public BvBounds(IToken/*!*/ tok, BigNum lower, BigNum upper) + : base(tok) { + Contract.Requires(tok != null); + this.Lower = lower; + this.Upper = upper; + } + public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result() != null); return Bpl.Type.Int; } } + public override void Resolve(ResolutionContext/*!*/ rc) { + // Contract.Requires(rc != null); + rc.Error(this, "bitvector bounds in illegal position"); + } + public override void Emit(TokenTextWriter/*!*/ stream, + int contextBindingStrength, bool fragileContext) { + Contract.Assert(false);throw new cce.UnreachableException(); + } + public override void ComputeFreeVariables(GSet/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); } +} + +/*--------------------------------------------------------------------------*/ +CHARACTERS + letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". + digit = "0123456789". + special = "'~#$^_.?`". + glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". + + cr = '\r'. + lf = '\n'. + tab = '\t'. + + space = ' '. + quote = '"'. + + newLine = cr + lf. + regularStringChar = ANY - quote - newLine. + + nondigit = letter + special. + nonquote = letter + digit + space + glyph. + + +/*------------------------------------------------------------------------*/ +TOKENS + ident = [ '\\' ] nondigit {nondigit | digit}. + bvlit = digit {digit} 'b' 'v' digit {digit}. + digits = digit {digit}. + + string = quote { regularStringChar | "\\\"" } quote. + + decimal = digit {digit} 'e' [ '-' ] digit {digit} . + float = digit {digit} '.' digit {digit} [ 'e' [ '-' ] digit {digit} ] . + +COMMENTS FROM "/*" TO "*/" NESTED +COMMENTS FROM "//" TO lf + +IGNORE cr + lf + tab + + +/*------------------------------------------------------------------------*/ +PRODUCTIONS + + +/*------------------------------------------------------------------------*/ +BoogiePL += (. List/*!*/ vs; + List/*!*/ ds; + Axiom/*!*/ ax; + List/*!*/ ts; + Procedure/*!*/ pr; + Implementation im; + Implementation/*!*/ nnim; + .) + { Consts (. foreach(Bpl.Variable/*!*/ v in vs){ + Contract.Assert(v != null); + Pgm.AddTopLevelDeclaration(v); + } + .) + | Function (. foreach(Bpl.Declaration/*!*/ d in ds){ + Contract.Assert(d != null); + Pgm.AddTopLevelDeclaration(d); + } + .) + | Axiom (. Pgm.AddTopLevelDeclaration(ax); .) + | UserDefinedTypes (. foreach(Declaration/*!*/ td in ts){ + Contract.Assert(td != null); + Pgm.AddTopLevelDeclaration(td); + } + .) + | GlobalVars (. foreach(Bpl.Variable/*!*/ v in vs){ + Contract.Assert(v != null); + Pgm.AddTopLevelDeclaration(v); + } + .) + | Procedure (. Pgm.AddTopLevelDeclaration(pr); + if (im != null) { + Pgm.AddTopLevelDeclaration(im); + } + .) + | Implementation (. Pgm.AddTopLevelDeclaration(nnim); .) + } + EOF + . + +/*------------------------------------------------------------------------*/ +GlobalVars<.out List/*!*/ ds.> += (. + Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + QKeyValue kv = null; + ds = new List(); + var dsx = ds; + .) + "var" + { Attribute } + IdsTypeWheres ";" + . + +LocalVars<.List/*!*/ ds.> += (. + Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + QKeyValue kv = null; + .) + "var" + { Attribute } + IdsTypeWheres ";" + . + +ProcFormals<.bool incoming, bool allowWhereClauses, out List/*!*/ ds.> += (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + ds = new List(); + var dsx = ds; + var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals"; + .) + "(" + [ AttrsIdsTypeWheres + ] + ")" + . + +BoundVars<.IToken/*!*/ x, out List/*!*/ ds.> += (. + Contract.Requires(x != null); + Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + List/*!*/ tyds = new List(); + ds = new List(); + var dsx = ds; + .) + AttrsIdsTypeWheres + . + +/*------------------------------------------------------------------------*/ +/* IdsType is used with const declarations */ +IdsType<.out List/*!*/ tyds.> += (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List/*!*/ ids; Bpl.Type/*!*/ ty; .) + Idents ":" Type + (. tyds = new List(); + foreach(Token/*!*/ id in ids){ + Contract.Assert(id != null); + tyds.Add(new TypedIdent(id, id.val, ty, null)); + } + .) + . + +/* AttrsIdsTypeWheres is used with the declarations of formals and bound variables */ +AttrsIdsTypeWheres<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> += + AttributesIdsTypeWhere + { "," AttributesIdsTypeWhere } + . + +IdsTypeWheres<. bool allowWhereClauses, string context, System.Action action .> += + IdsTypeWhere + { "," IdsTypeWhere } + . + +AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> += (. QKeyValue kv = null; .) + { Attribute (. if (!allowAttributes) { + kv = null; + this.SemErr("attributes are not allowed on " + context); + } + .) + } + IdsTypeWhere + . + +/* context is allowed to be null if allowWhereClauses is true */ +IdsTypeWhere<. bool allowWhereClauses, string context, System.Action action .> += (. List/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .) + Idents ":" Type + [ "where" Expression (. if (!allowWhereClauses) { + this.SemErr("where clause not allowed on " + context); + } else { + wh = nne; + } + .) + ] + (. foreach(Token/*!*/ id in ids){ + Contract.Assert(id != null); + action(new TypedIdent(id, id.val, ty, wh)); + } + .) + . + +/*------------------------------------------------------------------------*/ +Type += (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .) + ( + TypeAtom + | + Ident (. List/*!*/ args = new List (); .) + [ TypeArgs ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .) + | + MapType + ) + . + +TypeArgs<.List/*!*/ ts.> += (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .) + ( + TypeAtom (. ts.Add(ty); .) + [ TypeArgs ] + | + Ident (. List/*!*/ args = new List (); + ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .) + [ TypeArgs ] + | + MapType (. ts.Add(ty); .) + ) + . + +TypeAtom += (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType; .) + ( "int" (. ty = new BasicType(t, SimpleType.Int); .) + | "real" (. ty = new BasicType(t, SimpleType.Real); .) + | "bool" (. ty = new BasicType(t, SimpleType.Bool); .) + /* note: bitvectors are handled in UnresolvedTypeIdentifier */ + | + "(" + Type + ")" + ) + . + +MapType += (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null; + IToken/*!*/ nnTok; + List/*!*/ arguments = new List(); + Bpl.Type/*!*/ result; + List/*!*/ typeParameters = new List(); + .) + [ TypeParams (. tok = nnTok; .) ] + "[" (. if (tok == null) tok = t; .) + [ Types ] + "]" + Type + (. + ty = new MapType(tok, typeParameters, arguments, result); + .) + . + +TypeParams<.out IToken/*!*/ tok, out List/*!*/ typeParams.> += (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List/*!*/ typeParamToks; .) + "<" (. tok = t; .) + Idents + ">" + (. + typeParams = new List (); + foreach(Token/*!*/ id in typeParamToks){ + Contract.Assert(id != null); + typeParams.Add(new TypeVariable(id, id.val));} + .) + . + +Types<.List/*!*/ ts.> += (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .) + Type (. ts.Add(ty); .) + { "," Type (. ts.Add(ty); .) + } + . + + +/*------------------------------------------------------------------------*/ +Consts<.out List/*!*/ ds.> += (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List/*!*/ xs; + ds = new List(); + bool u = false; QKeyValue kv = null; + bool ChildrenComplete = false; + List Parents = null; .) + "const" (. y = t; .) + { Attribute } + [ "unique" (. u = true; .) + ] + IdsType + [ OrderSpec ] + (. bool makeClone = false; + foreach(TypedIdent/*!*/ x in xs){ + Contract.Assert(x != null); + + // ensure that no sharing is introduced + List ParentsClone; + if (makeClone && Parents != null) { + ParentsClone = new List (); + foreach (ConstantParent/*!*/ p in Parents){ + Contract.Assert(p != null); + ParentsClone.Add(new ConstantParent ( + new IdentifierExpr (p.Parent.tok, p.Parent.Name), + p.Unique));} + } else { + ParentsClone = Parents; + } + makeClone = true; + + ds.Add(new Constant(y, x, u, ParentsClone, ChildrenComplete, kv)); + } + .) + ";" + . + +OrderSpec<.out bool ChildrenComplete, out List Parents.> += (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false; + Parents = null; + bool u; + IToken/*!*/ parent; .) + "extends" (. Parents = new List (); + u = false; .) + [ + [ "unique" (. u = true; .) + ] + Ident (. Parents.Add(new ConstantParent ( + new IdentifierExpr(parent, parent.val), u)); .) + { + "," (. u = false; .) + [ "unique" (. u = true; .) + ] + Ident (. Parents.Add(new ConstantParent ( + new IdentifierExpr(parent, parent.val), u)); .) + } + ] + [ "complete" (. ChildrenComplete = true; .) + ] + . + +/*------------------------------------------------------------------------*/ +Function<.out List/*!*/ ds.> += (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); + ds = new List(); IToken/*!*/ z; + IToken/*!*/ typeParamTok; + var typeParams = new List(); + var arguments = new List(); + TypedIdent/*!*/ tyd; + TypedIdent retTyd = null; + Bpl.Type/*!*/ retTy; + QKeyValue argKv = null; + QKeyValue kv = null; + Expr definition = null; + Expr/*!*/ tmp; + .) + "function" { Attribute } Ident + [ TypeParams ] + "(" + [ VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) + { "," VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) + } ] ")" + (. argKv = null; .) + ( + "returns" "(" VarOrType ")" + | + ":" Type (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .) + ) + ( "{" Expression (. definition = tmp; .) "}" | ";" ) + (. + if (retTyd == null) { + // construct a dummy type for the case of syntax error + retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); + } + Function/*!*/ func = new Function(z, z.val, typeParams, arguments, + new Formal(retTyd.tok, retTyd, false, argKv), null, kv); + Contract.Assert(func != null); + ds.Add(func); + bool allUnnamed = true; + foreach(Formal/*!*/ f in arguments){ + Contract.Assert(f != null); + if (f.TypedIdent.HasName) { + allUnnamed = false; + break; + } + } + if (!allUnnamed) { + Bpl.Type prevType = null; + for (int i = arguments.Count; 0 <= --i; ) { + TypedIdent/*!*/ curr = cce.NonNull(arguments[i]).TypedIdent; + if (curr.HasName) { + // the argument was given as both an identifier and a type + prevType = curr.Type; + } else { + // the argument was given as just one "thing", which syntactically parsed as a type + if (prevType == null) { + this.errors.SemErr(curr.tok, "the type of the last parameter is unspecified"); + break; + } + Bpl.Type ty = curr.Type; + var uti = ty as UnresolvedTypeIdentifier; + if (uti != null && uti.Arguments.Count == 0) { + // the given "thing" was just an identifier, so let's use it as the name of the parameter + curr.Name = uti.Name; + curr.Type = prevType; + } else { + this.errors.SemErr(curr.tok, "expecting an identifier as parameter name"); + } + } + } + } + if (definition != null) { + // generate either an axiom or a function body + if (QKeyValue.FindBoolAttribute(kv, "inline")) { + func.Body = definition; + } else { + ds.Add(func.CreateDefinitionAxiom(definition, kv)); + } + } + .) + . + +VarOrType += (. + Contract.Ensures(Contract.ValueAtReturn(out tyd) != null); + string/*!*/ varName = TypedIdent.NoName; + Bpl.Type/*!*/ ty; + IToken/*!*/ tok; + kv = null; + .) + { Attribute } + Type (. tok = ty.tok; .) + [ ":" (. var uti = ty as UnresolvedTypeIdentifier; + if (uti != null && uti.Arguments.Count == 0) { + varName = uti.Name; + } else { + this.SemErr("expected identifier before ':'"); + } + .) + Type + ] + (. tyd = new TypedIdent(tok, varName, ty); .) + . + +/*------------------------------------------------------------------------*/ +Axiom += (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .) + "axiom" + { Attribute } + (. IToken/*!*/ x = t; .) + Proposition ";" (. m = new Axiom(x,e, null, kv); .) + . + +/*------------------------------------------------------------------------*/ +UserDefinedTypes<.out List/*!*/ ts.> += (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List (); .) + "type" + { Attribute } + UserDefinedType (. ts.Add(decl); .) + { "," UserDefinedType (. ts.Add(decl); .) } + ";" + . + +UserDefinedType += (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List/*!*/ paramTokens = new List (); + Bpl.Type/*!*/ body = dummyType; bool synonym = false; .) + Ident + [ WhiteSpaceIdents ] + [ + "=" Type + (. synonym = true; .) + ] + (. + if (synonym) { + List/*!*/ typeParams = new List(); + foreach(Token/*!*/ t in paramTokens){ + Contract.Assert(t != null); + typeParams.Add(new TypeVariable(t, t.val));} + decl = new TypeSynonymDecl(id, id.val, typeParams, body, kv); + } else { + decl = new TypeCtorDecl(id, id.val, paramTokens.Count, kv); + } + .) + . + + +/*------------------------------------------------------------------------*/ +Procedure += (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x; + List/*!*/ typeParams; + List/*!*/ ins, outs; + List/*!*/ pre = new List(); + List/*!*/ mods = new List(); + List/*!*/ post = new List(); + + List/*!*/ locals = new List(); + StmtList/*!*/ stmtList; + QKeyValue kv = null; + impl = null; + .) + + "procedure" + ProcSignature + ( ";" + { Spec } + | { Spec } + ImplBody + (. + impl = new Implementation(x, x.val, typeParams, + Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); + .) + ) + (. proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); .) + . + + +Implementation += (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x; + List/*!*/ typeParams; + List/*!*/ ins, outs; + List/*!*/ locals; + StmtList/*!*/ stmtList; + QKeyValue kv; + .) + + "implementation" + ProcSignature + ImplBody + (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .) + . + + +ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List/*!*/ typeParams, + out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv.> += (. Contract.Ensures(Contract.ValueAtReturn(out name) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ins) != null); Contract.Ensures(Contract.ValueAtReturn(out outs) != null); + IToken/*!*/ typeParamTok; typeParams = new List(); + outs = new List(); kv = null; .) + { Attribute } + Ident + [ TypeParams ] + ProcFormals + [ "returns" ProcFormals ] + . + + +Spec<.List/*!*/ pre, List/*!*/ mods, List/*!*/ post.> += (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List/*!*/ ms; .) + ( "modifies" + [ Idents (. foreach(IToken/*!*/ m in ms){ + Contract.Assert(m != null); + mods.Add(new IdentifierExpr(m, m.val)); + } + .) + ] ";" + | "free" SpecPrePost + | SpecPrePost + ) + . + +SpecPrePost<.bool free, List/*!*/ pre, List/*!*/ post.> += (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .) + ( "requires" (. tok = t; .) + { Attribute } + Proposition ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .) + | "ensures" (. tok = t; .) + { Attribute } + Proposition ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .) + ) + . + +/*------------------------------------------------------------------------*/ + +ImplBody<.out List/*!*/ locals, out StmtList/*!*/ stmtList.> += (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List(); .) + "{" + { LocalVars } + StmtList + . + +/* the StmtList also reads the final curly brace */ +StmtList += (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List bigblocks = new List(); + /* built-up state for the current BigBlock: */ + IToken startToken = null; string currentLabel = null; + List cs = null; /* invariant: startToken != null ==> cs != null */ + /* temporary variables: */ + IToken label; Cmd c; BigBlock b; + StructuredCmd ec = null; StructuredCmd/*!*/ ecn; + TransferCmd tc = null; TransferCmd/*!*/ tcn; + .) + + { + ( LabelOrCmd + (. if (c != null) { + // LabelOrCmd read a Cmd + Contract.Assert(label == null); + if (startToken == null) { startToken = c.tok; cs = new List(); } + Contract.Assert(cs != null); + cs.Add(c); + } else { + // LabelOrCmd read a label + Contract.Assert(label != null); + if (startToken != null) { + Contract.Assert(cs != null); + // dump the built-up state into a BigBlock + b = new BigBlock(startToken, currentLabel, cs, null, null); + bigblocks.Add(b); + cs = null; + } + startToken = label; + currentLabel = label.val; + cs = new List(); + } + .) + + | StructuredCmd + (. ec = ecn; + if (startToken == null) { startToken = ec.tok; cs = new List(); } + Contract.Assert(cs != null); + b = new BigBlock(startToken, currentLabel, cs, ec, null); + bigblocks.Add(b); + startToken = null; currentLabel = null; cs = null; + .) + + | TransferCmd + (. tc = tcn; + if (startToken == null) { startToken = tc.tok; cs = new List(); } + Contract.Assert(cs != null); + b = new BigBlock(startToken, currentLabel, cs, null, tc); + bigblocks.Add(b); + startToken = null; currentLabel = null; cs = null; + .) + + ) + } + "}" + (. IToken/*!*/ endCurly = t; + if (startToken == null && bigblocks.Count == 0) { + startToken = t; cs = new List(); + } + if (startToken != null) { + Contract.Assert(cs != null); + b = new BigBlock(startToken, currentLabel, cs, null, null); + bigblocks.Add(b); + } + + stmtList = new StmtList(bigblocks, endCurly); + .) + . + +TransferCmd += (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd; + Token y; List/*!*/ xs; + List ss = new List(); + .) + ( "goto" (. y = t; .) + Idents (. foreach(IToken/*!*/ s in xs){ + Contract.Assert(s != null); + ss.Add(s.val); } + tc = new GotoCmd(y, ss); + .) + | "return" (. tc = new ReturnCmd(t); .) + ) ";" + . + +StructuredCmd += (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec)); + IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd; + .) + ( IfCmd (. ec = ifcmd; .) + | WhileCmd (. ec = wcmd; .) + | BreakCmd (. ec = bcmd; .) + ) + . + +IfCmd += (. Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x; + Expr guard; + StmtList/*!*/ thn; + IfCmd/*!*/ elseIf; IfCmd elseIfOption = null; + StmtList/*!*/ els; StmtList elseOption = null; + .) + "if" (. x = t; .) + Guard + "{" StmtList + [ "else" + ( IfCmd (. elseIfOption = elseIf; .) + | "{" + StmtList (. elseOption = els; .) + ) + ] + (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .) + . + +WhileCmd += (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z; + Expr guard; Expr/*!*/ e; bool isFree; + List invariants = new List(); + StmtList/*!*/ body; + QKeyValue kv = null; + .) + "while" (. x = t; .) + Guard (. Contract.Assume(guard == null || cce.Owner.None(guard)); .) + { (. isFree = false; z = la/*lookahead token*/; .) + [ "free" (. isFree = true; .) + ] + "invariant" + { Attribute } + Expression (. if (isFree) { + invariants.Add(new AssumeCmd(z, e, kv)); + } else { + invariants.Add(new AssertCmd(z, e, kv)); + } + kv = null; + .) + ";" + } + "{" + StmtList (. wcmd = new WhileCmd(x, guard, invariants, body); .) + . + +Guard += (. Expr/*!*/ ee; e = null; .) + "(" + ( "*" (. e = null; .) + | Expression (. e = ee; .) + ) + ")" + . + +BreakCmd += (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y; + string breakLabel = null; + .) + "break" (. x = t; .) + [ Ident (. breakLabel = y.val; .) + ] ";" (. bcmd = new BreakCmd(x, breakLabel); .) + . + +/*------------------------------------------------------------------------*/ + +LabelOrCmd +/* ensures (c == null) != (label != null) */ += (. IToken/*!*/ x; Expr/*!*/ e; + List/*!*/ xs; + List ids; + c = dummyCmd; label = null; + Cmd/*!*/ cn; + QKeyValue kv = null; + .) + ( LabelOrAssign + | "assert" (. x = t; .) + { Attribute } + Proposition (. c = new AssertCmd(x, e, kv); .) + ";" + | "assume" (. x = t; .) + { Attribute } + Proposition (. c = new AssumeCmd(x, e, kv); .) + ";" + | "havoc" (. x = t; .) + Idents ";" (. ids = new List(); + foreach(IToken/*!*/ y in xs){ + Contract.Assert(y != null); + ids.Add(new IdentifierExpr(y, y.val)); + } + c = new HavocCmd(x,ids); + .) + | CallCmd ";" (. c = cn; .) + | ParCallCmd (. c = cn; .) + | "yield" (. x = t; .) + ";" (. c = new YieldCmd(x); .) + ) + . + +/*------------------------------------------------------------------------*/ + +LabelOrAssign +/* ensures (c == null) != (label != null) */ += (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0; + c = dummyCmd; label = null; + AssignLhs/*!*/ lhs; + List/*!*/ lhss; + List/*!*/ rhss; + List/*!*/ indexes; + .) + Ident (. x = t; .) + ( ":" (. c = null; label = x; .) + + | (. lhss = new List(); .) + (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) + + { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } + (. lhss.Add(lhs); .) + + { "," + Ident + (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) + { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } + (. lhss.Add(lhs); .) + } + + ":=" (. x = t; /* use location of := */ .) + Expression (. rhss = new List (); + rhss.Add(e0); .) + { "," + Expression (. rhss.Add(e0); .) + } + ";" (. c = new AssignCmd(x, lhss, rhss); .) + ) + . + +MapAssignIndex<.out IToken/*!*/ x, out List/*!*/ indexes.> += (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List (); + Expr/*!*/ e; + .) + "[" (. x = t; .) + [ + Expression (. indexes.Add(e); .) + { "," + Expression (. indexes.Add(e); .) + } + ] + "]" + . + +/*------------------------------------------------------------------------*/ +CallCmd += (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); + IToken x; + bool isAsync = false; + bool isFree = false; + QKeyValue kv = null; + c = null; + .) + [ "async" (. isAsync = true; .) + ] + [ "free" (. isFree = true; .) + ] + "call" (. x = t; .) + { Attribute } + CallParams (. .) + . + +ParCallCmd += (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); + IToken x; + QKeyValue kv = null; + Cmd c = null; + List callCmds = new List(); + .) + "par" (. x = t; .) + { Attribute } + CallParams (. callCmds.Add((CallCmd)c); .) + { "|" CallParams (. callCmds.Add((CallCmd)c); .) + } + ";" (. d = new ParCallCmd(x, callCmds, kv); .) + . + +CallParams += (. + List ids = new List(); + List es = new List(); + Expr en; + IToken first; + IToken p; + c = null; + .) + Ident + ( "(" + [ Expression (. es.Add(en); .) + { "," Expression (. es.Add(en); .) + } + ] + ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) + | + (. ids.Add(new IdentifierExpr(first, first.val)); .) + [ "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) + { "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) + } + ] ":=" + Ident "(" + [ Expression (. es.Add(en); .) + { "," Expression (. es.Add(en); .) + } + ] + ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) + ) + . + +/*------------------------------------------------------------------------*/ +Proposition +=(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.) + Expression + . + +/*------------------------------------------------------------------------*/ +Idents<.out List/*!*/ xs.> += (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) + Ident (. xs.Add(id); .) + { "," Ident (. xs.Add(id); .) + } + . + +/*------------------------------------------------------------------------*/ +WhiteSpaceIdents<.out List/*!*/ xs.> += (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) + Ident (. xs.Add(id); .) + { Ident (. xs.Add(id); .) + } + . + +/*------------------------------------------------------------------------*/ +Expressions<.out List/*!*/ es.> += (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List(); .) + Expression (. es.Add(e); .) + { "," Expression (. es.Add(e); .) + } + . + +/*------------------------------------------------------------------------*/ +Expression<.out Expr/*!*/ e0.> += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + ImpliesExpression + { EquivOp (. x = t; .) + ImpliesExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .) + } + . + +EquivOp = "<==>" | '\u21d4'. + +/*------------------------------------------------------------------------*/ +ImpliesExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + LogicalExpression + [ + ImpliesOp (. x = t; .) + /* recurse because implication is right-associative */ + ImpliesExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1); .) + | + ExpliesOp (. if (noExplies) + this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate"); + x = t; .) + LogicalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) + /* loop because explies is left-associative */ + { + ExpliesOp (. x = t; .) + LogicalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) + } + ] + . + +ImpliesOp = "==>" | '\u21d2'. +ExpliesOp = "<==" | '\u21d0'. + +/*------------------------------------------------------------------------*/ +LogicalExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + RelationalExpression + [ AndOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) + { AndOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) + } + | OrOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) + { OrOp (. x = t; .) + RelationalExpression + (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) + } + ] + . + +AndOp = "&&" | '\u2227'. +OrOp = "||" | '\u2228'. + +/*------------------------------------------------------------------------*/ +RelationalExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) + BvTerm + [ RelOp + BvTerm (. e0 = Expr.Binary(x, op, e0, e1); .) + ] + . + +RelOp += (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) + ( "==" (. x = t; op=BinaryOperator.Opcode.Eq; .) + | "<" (. x = t; op=BinaryOperator.Opcode.Lt; .) + | ">" (. x = t; op=BinaryOperator.Opcode.Gt; .) + | "<=" (. x = t; op=BinaryOperator.Opcode.Le; .) + | ">=" (. x = t; op=BinaryOperator.Opcode.Ge; .) + | "!=" (. x = t; op=BinaryOperator.Opcode.Neq; .) + | "<:" (. x = t; op=BinaryOperator.Opcode.Subtype; .) + | '\u2260' (. x = t; op=BinaryOperator.Opcode.Neq; .) + | '\u2264' (. x = t; op=BinaryOperator.Opcode.Le; .) + | '\u2265' (. x = t; op=BinaryOperator.Opcode.Ge; .) + ) + . + +/*------------------------------------------------------------------------*/ +BvTerm += (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + Term + { "++" (. x = t; .) + Term (. e0 = new BvConcatExpr(x, e0, e1); .) + } + . + + +/*------------------------------------------------------------------------*/ +Term += (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) + Factor + { AddOp + Factor (. e0 = Expr.Binary(x, op, e0, e1); .) + } + . + +AddOp += (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) + ( "+" (. x = t; op=BinaryOperator.Opcode.Add; .) + | "-" (. x = t; op=BinaryOperator.Opcode.Sub; .) + ) + . + +/*------------------------------------------------------------------------*/ +Factor += (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) + Power + { MulOp + Power (. e0 = Expr.Binary(x, op, e0, e1); .) + } + . + +MulOp += (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) + ( "*" (. x = t; op=BinaryOperator.Opcode.Mul; .) + | "div" (. x = t; op=BinaryOperator.Opcode.Div; .) + | "mod" (. x = t; op=BinaryOperator.Opcode.Mod; .) + | "/" (. x = t; op=BinaryOperator.Opcode.RealDiv; .) + ) + . + +/*------------------------------------------------------------------------*/ +Power += (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) + UnaryExpression + [ + "**" (. x = t; .) + /* recurse because exponentation is right-associative */ + Power (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .) + ] + . + +/*------------------------------------------------------------------------*/ +UnaryExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; + e = dummyExpr; + .) + ( "-" (. x = t; .) + UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .) + | NegOp (. x = t; .) + UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .) + | CoercionExpression + ) + . + +NegOp = "!" | '\u00ac'. + +/*------------------------------------------------------------------------*/ + +/* This production creates ambiguities, because types can start with "<" + (polymorphic map types), but can also be followed by "<" (inequalities). + Coco deals with these ambiguities in a reasonable way by preferring to read + further types (type arguments) over relational symbols. E.g., "5 : C < 0" + will cause a parse error because "<" is treated as the beginning of a + map type. */ + +CoercionExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; + Bpl.Type/*!*/ coercedTo; + BigNum bn; + .) + ArrayExpression + { ":" (. x = t; .) + ( + Type (. e = Expr.CoerceType(x, e, coercedTo); .) + | + Nat /* This means that we really look at a bitvector + expression t[a:b] */ + (. if (!(e is LiteralExpr) || !((LiteralExpr)e).isBigNum) { + this.SemErr("arguments of extract need to be integer literals"); + e = new BvBounds(x, bn, BigNum.ZERO); + } else { + e = new BvBounds(x, bn, ((LiteralExpr)e).asBigNum); + } + .) + ) + } + . + +/*------------------------------------------------------------------------*/ +ArrayExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; + Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1; + bool store; bool bvExtract; + List/*!*/ allArgs = dummyExprSeq; + .) + AtomExpression + { "[" (. x = t; allArgs = new List (); + allArgs.Add(e); + store = false; bvExtract = false; .) + [ + Expression + (. if (index0 is BvBounds) + bvExtract = true; + else + allArgs.Add(index0); + .) + { "," Expression + (. if (bvExtract || e1 is BvBounds) + this.SemErr("bitvectors only have one dimension"); + allArgs.Add(e1); + .) + } + [ ":=" Expression + (. if (bvExtract || e1 is BvBounds) + this.SemErr("assignment to bitvectors is not possible"); + allArgs.Add(e1); store = true; + .) + ] + | ":=" Expression (. allArgs.Add(e1); store = true; .) + ] + "]" + (. if (store) + e = new NAryExpr(x, new MapStore(x, allArgs.Count - 2), allArgs); + else if (bvExtract) + e = new BvExtractExpr(x, e, + ((BvBounds)index0).Upper.ToIntSafe, + ((BvBounds)index0).Lower.ToIntSafe); + else + e = new NAryExpr(x, new MapSelect(x, allArgs.Count - 1), allArgs); + .) + } + . + + +/*------------------------------------------------------------------------*/ +AtomExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; + List/*!*/ es; List/*!*/ ds; Trigger trig; + List/*!*/ typeParams; + IdentifierExpr/*!*/ id; + QKeyValue kv; + e = dummyExpr; + List/*!*/ locals; + List/*!*/ blocks; + .) + ( "false" (. e = new LiteralExpr(t, false); .) + | "true" (. e = new LiteralExpr(t, true); .) + | Nat (. e = new LiteralExpr(t, bn); .) + | Dec (. e = new LiteralExpr(t, bd); .) + | BvLit (. e = new LiteralExpr(t, bn, n); .) + + | Ident (. id = new IdentifierExpr(x, x.val); e = id; .) + [ "(" + ( Expressions (. e = new NAryExpr(x, new FunctionCall(id), es); .) + | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List()); .) + ) + ")" + ] + + | "old" (. x = t; .) + "(" + Expression + ")" (. e = new OldExpr(x, e); .) + + | "int" (. x = t; .) + "(" + Expression + ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List{ e }); .) + + | "real" (. x = t; .) + "(" + Expression + ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); .) + + | "(" ( Expression (. if (e is BvBounds) + this.SemErr("parentheses around bitvector bounds " + + "are not allowed"); .) + | Forall (. x = t; .) + QuantifierBody + (. if (typeParams.Count + ds.Count > 0) + e = new ForallExpr(x, typeParams, ds, kv, trig, e); .) + | Exists (. x = t; .) + QuantifierBody + (. if (typeParams.Count + ds.Count > 0) + e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .) + | Lambda (. x = t; .) + QuantifierBody + (. if (trig != null) + SemErr("triggers not allowed in lambda expressions"); + if (typeParams.Count + ds.Count > 0) + e = new LambdaExpr(x, typeParams, ds, kv, e); .) + ) + ")" + | IfThenElseExpression + | CodeExpression (. e = new CodeExpr(locals, blocks); .) + ) + . + +CodeExpression<.out List/*!*/ locals, out List/*!*/ blocks.> += (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List(); Block/*!*/ b; + blocks = new List(); + .) + "|{" + { LocalVars } + SpecBlock (. blocks.Add(b); .) + { SpecBlock (. blocks.Add(b); .) + } + "}|" + . + +SpecBlock += (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y; + Cmd c; IToken label; + List cs = new List(); + List/*!*/ xs; + List ss = new List(); + b = dummyBlock; + Expr/*!*/ e; + .) + Ident ":" + { LabelOrCmd + (. if (c != null) { + Contract.Assert(label == null); + cs.Add(c); + } else { + Contract.Assert(label != null); + SemErr("SpecBlock's can only have one label"); + } + .) + } + ( "goto" (. y = t; .) + Idents (. foreach(IToken/*!*/ s in xs){ + Contract.Assert(s != null); + ss.Add(s.val); } + b = new Block(x,x.val,cs,new GotoCmd(y,ss)); + .) + | "return" Expression + (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .) + ) + ";" + . + +Attribute += (. Trigger trig = null; .) + AttributeOrTrigger (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .) +. + +AttributeOrTrigger += (. IToken/*!*/ tok; Expr/*!*/ e; List/*!*/ es; + string key; + List parameters; object/*!*/ param; + .) + "{" (. tok = t; .) + ( + ":" ident (. key = t.val; parameters = new List(); .) + [ AttributeParameter (. parameters.Add(param); .) + { "," AttributeParameter (. parameters.Add(param); .) + } + ] + (. if (key == "nopats") { + if (parameters.Count == 1 && parameters[0] is Expr) { + e = (Expr)parameters[0]; + if(trig==null){ + trig = new Trigger(tok, false, new List { e }, null); + } else { + trig.AddLast(new Trigger(tok, false, new List { e }, null)); + } + } else { + this.SemErr("the 'nopats' quantifier attribute expects a string-literal parameter"); + } + } else { + if (kv==null) { + kv = new QKeyValue(tok, key, parameters, null); + } else { + kv.AddLast(new QKeyValue(tok, key, parameters, null)); + } + } + .) + | + Expression (. es = new List { e }; .) + { "," Expression (. es.Add(e); .) + } (. if (trig==null) { + trig = new Trigger(tok, true, es, null); + } else { + trig.AddLast(new Trigger(tok, true, es, null)); + } + .) + ) + "}" + . + +AttributeParameter += (. Contract.Ensures(Contract.ValueAtReturn(out o) != null); + o = "error"; + Expr/*!*/ e; + .) + ( string (. o = t.val.Substring(1, t.val.Length-2); .) + | Expression (. o = e; .) + ) + . + +IfThenElseExpression += (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); + IToken/*!*/ tok; + Expr/*!*/ e0, e1, e2; + e = dummyExpr; .) + "if" (. tok = t; .) Expression "then" Expression "else" Expression + (. e = new NAryExpr(tok, new IfThenElse(tok), new List{ e0, e1, e2 }); .) + . + + +QuantifierBody<.IToken/*!*/ q, out List/*!*/ typeParams, out List/*!*/ ds, + out QKeyValue kv, out Trigger trig, out Expr/*!*/ body.> += (. Contract.Requires(q != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); Contract.Ensures(Contract.ValueAtReturn(out body) != null); + trig = null; typeParams = new List (); + IToken/*!*/ tok; + kv = null; + ds = new List (); + .) + ( + TypeParams + [ BoundVars ] + | + BoundVars + ) + QSep + { AttributeOrTrigger } + Expression + . + +Forall = "forall" | '\u2200'. +Exists = "exists" | '\u2203'. +Lambda = "lambda" | '\u03bb'. +QSep = "::" | '\u2022'. + +/*------------------------------------------------------------------------*/ +Ident +=(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.) + ident (. x = t; + if (x.val.StartsWith("\\")) + x.val = x.val.Substring(1); + .) + . + +/*------------------------------------------------------------------------*/ +Nat += + digits + (. try { + n = BigNum.FromString(t.val); + } catch (FormatException) { + this.SemErr("incorrectly formatted number"); + n = BigNum.ZERO; + } + .) + . + +/*------------------------------------------------------------------------*/ +Dec += (. string s = ""; .) + ( + decimal (. s = t.val; .) + | + float (. s = t.val; .) + ) + (. try { + n = BigDec.FromString(s); + } catch (FormatException) { + this.SemErr("incorrectly formatted number"); + n = BigDec.ZERO; + } + .) + . + +/*------------------------------------------------------------------------*/ +BvLit += + bvlit + (. + int pos = t.val.IndexOf("bv"); + string a = t.val.Substring(0, pos); + string b = t.val.Substring(pos + 2); + try { + n = BigNum.FromString(a); + m = Convert.ToInt32(b); + } catch (FormatException) { + this.SemErr("incorrectly formatted bitvector"); + n = BigNum.ZERO; + m = 0; + } + .) + . +END BoogiePL. diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index 309aab0e..1c7f40d4 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -1,2169 +1,2169 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Diagnostics; -using System.Diagnostics.Contracts; - -namespace Microsoft.Boogie { - public class CommandLineOptionEngine - { - public readonly string ToolName; - public readonly string DescriptiveToolName; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(ToolName != null); - Contract.Invariant(DescriptiveToolName != null); - Contract.Invariant(this._environment != null); - Contract.Invariant(cce.NonNullElements(this._files)); - Contract.Invariant(this._fileTimestamp != null); - } - - private string/*!*/ _environment = ""; - - public string Environment { - get { - Contract.Ensures(Contract.Result() != null); - return this._environment; - } - set { - Contract.Requires(value != null); - this._environment = value; - } - } - - private readonly List/*!*/ _files = new List(); - - public IList/*!*/ Files { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - Contract.Ensures(Contract.Result>().IsReadOnly); - return this._files.AsReadOnly(); - } - } - - public bool HelpRequested = false; - public bool AttrHelpRequested = false; - - public CommandLineOptionEngine(string toolName, string descriptiveName) { - Contract.Requires(toolName != null); - Contract.Requires(descriptiveName != null); - ToolName = toolName; - DescriptiveToolName = descriptiveName; - } - - public virtual string/*!*/ VersionNumber { - get { - Contract.Ensures(Contract.Result() != null); - return cce.NonNull(cce.NonNull(System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location)).FileVersion); - } - } - public virtual string/*!*/ VersionSuffix { - get { - Contract.Ensures(Contract.Result() != null); - return " version " + VersionNumber + ", Copyright (c) 2003-2014, Microsoft."; - } - } - public virtual string/*!*/ Version { - get { - Contract.Ensures(Contract.Result() != null); - return DescriptiveToolName + VersionSuffix; - } - } - - private string/*!*/ _fileTimestamp = cce.NonNull(DateTime.Now.ToString("o")).Replace(':', '.'); - - public string FileTimestamp { - get { - Contract.Ensures(Contract.Result() != null); - return this._fileTimestamp; - } - set { - Contract.Requires(value != null); - this._fileTimestamp = value; - } - } - - public void ExpandFilename(ref string pattern, string logPrefix, string fileTimestamp) { - if (pattern != null) { - pattern = pattern.Replace("@PREFIX@", logPrefix).Replace("@TIME@", fileTimestamp); - string fn = Files.Count == 0 ? "" : Files[Files.Count - 1]; - fn = fn.Replace('/', '-').Replace('\\', '-'); - pattern = pattern.Replace("@FILE@", fn); - } - } - - /// - /// Process the option and modify "ps" accordingly. - /// Return true if the option is one that is recognized. - /// - protected virtual bool ParseOption(string name, CommandLineParseState ps) { - Contract.Requires(name != null); - Contract.Requires(ps != null); - - switch (name) { - case "help": - case "?": - if (ps.ConfirmArgumentCount(0)) { - HelpRequested = true; - } - return true; - case "attrHelp": - if (ps.ConfirmArgumentCount(0)) { - AttrHelpRequested = true; - } - return true; - default: - break; - } - return false; // unrecognized option - } - - protected class CommandLineParseState - { - public string s; - public bool hasColonArgument; - public readonly string[]/*!*/ args; - public int i; - public int nextIndex; - public bool EncounteredErrors; - public readonly string ToolName; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(args != null); - Contract.Invariant(0 <= i && i <= args.Length); - Contract.Invariant(0 <= nextIndex && nextIndex <= args.Length); - } - - - public CommandLineParseState(string[] args, string toolName) { - Contract.Requires(args != null); - Contract.Requires(Contract.ForAll(0, args.Length, i => args[i] != null)); - Contract.Requires(toolName != null); - Contract.Ensures(this.args == args); - this.ToolName = toolName; - this.s = null; // set later by client - this.hasColonArgument = false; // set later by client - this.args = args; - this.i = 0; - this.nextIndex = 0; // set later by client - this.EncounteredErrors = false; - } - - public bool CheckBooleanFlag(string flagName, ref bool flag, bool valueWhenPresent) { - Contract.Requires(flagName != null); - //modifies nextIndex, encounteredErrors, Console.Error.*; - bool flagPresent = false; - - if ((s == "/" + flagName || s == "-" + flagName) && ConfirmArgumentCount(0)) { - flag = valueWhenPresent; - flagPresent = true; - } - return flagPresent; - } - - public bool CheckBooleanFlag(string flagName, ref bool flag) { - Contract.Requires(flagName != null); - //modifies nextIndex, encounteredErrors, Console.Error.*; - return CheckBooleanFlag(flagName, ref flag, true); - } - - /// - /// If there is one argument and it is a non-negative integer, then set "arg" to that number and return "true". - /// Otherwise, emit error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref int arg) { - //modifies nextIndex, encounteredErrors, Console.Error.*; - return GetNumericArgument(ref arg, a => 0 <= a); - } - - /// - /// If there is one argument and the filtering predicate holds, then set "arg" to that number and return "true". - /// Otherwise, emit error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref int arg, Predicate filter) { - Contract.Requires(filter != null); - - if (this.ConfirmArgumentCount(1)) { - try { - Contract.Assume(args[i] != null); - Contract.Assert(args[i] is string); // needed to prove args[i].IsPeerConsistent - int d = Convert.ToInt32(this.args[this.i]); - if (filter == null || filter(d)) { - arg = d; - return true; - } - } catch (System.FormatException) { - } catch (System.OverflowException) { - } - } else { - return false; - } - Error("Invalid argument \"{0}\" to option {1}", args[this.i], this.s); - return false; - } - - /// - /// If there is one argument and it is a non-negative integer less than "limit", - /// then set "arg" to that number and return "true". - /// Otherwise, emit error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref int arg, int limit) { - Contract.Requires(this.i < args.Length); - Contract.Ensures(Math.Min(arg, 0) <= Contract.ValueAtReturn(out arg) && Contract.ValueAtReturn(out arg) < limit); - //modifies nextIndex, encounteredErrors, Console.Error.*; - int a = arg; - if (!GetNumericArgument(ref a)) { - return false; - } else if (a < limit) { - arg = a; - return true; - } else { - Error("Invalid argument \"{0}\" to option {1}", args[this.i], this.s); - return false; - } - } - - /// - /// If there is one argument and it is a non-negative real, then set "arg" to that number and return "true". - /// Otherwise, emit an error message, leave "arg" unchanged, and return "false". - /// - public bool GetNumericArgument(ref double arg) { - Contract.Ensures(Contract.ValueAtReturn(out arg) >= 0); - //modifies nextIndex, encounteredErrors, Console.Error.*; - if (this.ConfirmArgumentCount(1)) { - try { - Contract.Assume(args[i] != null); - Contract.Assert(args[i] is string); // needed to prove args[i].IsPeerConsistent - double d = Convert.ToDouble(this.args[this.i]); - if (0 <= d) { - arg = d; - return true; - } - } catch (System.FormatException) { - } catch (System.OverflowException) { - } - } else { - return false; - } - Error("Invalid argument \"{0}\" to option {1}", args[this.i], this.s); - return false; - } - - public bool ConfirmArgumentCount(int argCount) { - Contract.Requires(0 <= argCount); - //modifies nextIndex, encounteredErrors, Console.Error.*; - Contract.Ensures(Contract.Result() == (!(hasColonArgument && argCount != 1) && !(args.Length < i + argCount))); - if (hasColonArgument && argCount != 1) { - Error("\"{0}\" cannot take a colon argument", s); - nextIndex = args.Length; - return false; - } else if (args.Length < i + argCount) { - Error("\"{0}\" expects {1} argument{2}", s, argCount.ToString(), (string)(argCount == 1 ? "" : "s")); - nextIndex = args.Length; - return false; - } else { - nextIndex = i + argCount; - return true; - } - } - - public void Error(string message, params string[] args) { - Contract.Requires(args != null); - Contract.Requires(message != null); - //modifies encounteredErrors, Console.Error.*; - Console.Error.WriteLine("{0}: Error: {1}", ToolName, String.Format(message, args)); - EncounteredErrors = true; - } - } - - public virtual void Usage() { - Console.WriteLine("{0}: usage: {0} [ option ... ] [ filename ... ]", ToolName); - Console.WriteLine(@" where