Skip to content

Commit

Permalink
Introduce {:isolate} and {:isolate "paths"} attributes for assert…
Browse files Browse the repository at this point in the history
… and return commands (#952)

### Changes
- Introduce the `{:isolate}` attribute on AssertCmd and `ReturnCmd`
- Introduce the `{:isolate "paths"}` attribute on AssertCmd and
`ReturnCmd`
- Introduce new tokens that allow precisely describing where a
particular Split comes from.
- Fix a bug that caused too many VCs to be created when using
`/vcsSplitOnEveryAssert` together with focus
- Fix incorrect token bug for VCs originating from focus.

### Testing
- Created a folder `Test/implementationDivision` that has tests for
`{:isolate}`, `{:isolate "paths"}`, `{:focus}` and `{:split_here}`

---------

Co-authored-by: Mikaël Mayer <MikaelMayer@users.noreply.github.com>
  • Loading branch information
keyboardDrummer and MikaelMayer authored Oct 7, 2024
1 parent 9a8ce8d commit 25160fa
Show file tree
Hide file tree
Showing 77 changed files with 1,663 additions and 858 deletions.
6 changes: 4 additions & 2 deletions Source/Concurrency/CivlUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,14 +307,16 @@ public static HavocCmd HavocCmd(params IdentifierExpr[] vars)

public static class BlockHelper
{
public static readonly IToken /*!*/ ReportedNoToken = new Token();

public static Block Block(string label, List<Cmd> cmds)
{
return new Block(Token.NoToken, label, cmds, CmdHelper.ReturnCmd);
return new Block(ReportedNoToken, label, cmds, CmdHelper.ReturnCmd);
}

public static Block Block(string label, List<Cmd> cmds, List<Block> gotoTargets)
{
return new Block(Token.NoToken, label, cmds, new GotoCmd(Token.NoToken, gotoTargets));
return new Block(ReportedNoToken, label, cmds, new GotoCmd(Token.NoToken, gotoTargets));
}
}

Expand Down
9 changes: 6 additions & 3 deletions Source/Core/AST/AbsyCmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,9 @@ int FreshAnon()
return anon++;
}

HashSet<string /*!*/> allLabels = new HashSet<string /*!*/>();
private readonly HashSet<string /*!*/> allLabels = new();

Errors /*!*/
errorHandler;
private readonly Errors /*!*/ errorHandler;

[ContractInvariantMethod]
void ObjectInvariant()
Expand Down Expand Up @@ -3445,6 +3444,8 @@ public override void Emit(TokenTextWriter stream, int level)

public class ReturnCmd : TransferCmd
{
public QKeyValue Attributes { get; set; }

public ReturnCmd(IToken /*!*/ tok)
: base(tok)
{
Expand Down Expand Up @@ -3476,6 +3477,8 @@ public class GotoCmd : TransferCmd
[Rep] public List<String> LabelNames;
[Rep] public List<Block> LabelTargets;

public QKeyValue Attributes { get; set; }

[ContractInvariantMethod]
void ObjectInvariant()
{
Expand Down
6 changes: 5 additions & 1 deletion Source/Core/AST/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ public bool IsLive(Variable v)
return liveVarsBefore.Contains(v);
}

public Block(IToken tok)
public static Block ShallowClone(Block block) {
return new Block(block.tok, block.Label, block.Cmds, block.TransferCmd);
}

public Block(IToken tok, TransferCmd cmd)
: this(tok, "", new List<Cmd>(), new ReturnCmd(tok))
{
}
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/AST/CallCmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ protected override Cmd ComputeDesugaring(PrintOptions options)
Contract.Assert(a != null);
// These probably won't have IDs, but copy if they do.
if (callId is not null) {
a.CopyIdWithModificationsFrom(tok, req,
(a as ICarriesAttributes).CopyIdWithModificationsFrom(tok, req,
id => new TrackedCallRequiresAssumed(callId, id));
}

Expand Down Expand Up @@ -1066,7 +1066,7 @@ protected override Cmd ComputeDesugaring(PrintOptions options)
#endregion

if (callId is not null) {
assume.CopyIdWithModificationsFrom(tok, e,
(assume as ICarriesAttributes).CopyIdWithModificationsFrom(tok, e,
id => new TrackedCallEnsures(callId, id));
}

Expand Down
14 changes: 8 additions & 6 deletions Source/Core/AST/ICarriesAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,25 @@ public void AddStringAttribute(IToken tok, string name, string parameter)
Attributes = new QKeyValue(tok, name, new List<object>() {parameter}, Attributes);
}


}

public static class CarriesAttributesExtensions
{
public static void CopyIdFrom(this ICarriesAttributes dest, IToken tok, ICarriesAttributes src)
public static class CarriesAttributesExtensions {
public static void CopyIdFrom(this ICarriesAttributes destination, IToken tok, ICarriesAttributes src)
{
var id = src.FindStringAttribute("id");
if (id is not null) {
dest.AddStringAttribute(tok, "id", id);
destination.AddStringAttribute(tok, "id", id);
}
}

public static void CopyIdWithModificationsFrom(this ICarriesAttributes dest, IToken tok, ICarriesAttributes src, Func<string,TrackedNodeComponent> modifier)
public static void CopyIdWithModificationsFrom(this ICarriesAttributes destination, IToken tok,
ICarriesAttributes src, Func<string,TrackedNodeComponent> modifier)
{
var id = src.FindStringAttribute("id");
if (id is not null) {
dest.AddStringAttribute(tok, "id", modifier(id).SolverLabel);
destination.AddStringAttribute(tok, "id", modifier(id).SolverLabel);
}
}
}
8 changes: 4 additions & 4 deletions Source/Core/AST/Implementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,19 +462,19 @@ void BlocksWriters(TokenTextWriter stream) {
}

public void EmitImplementation(TokenTextWriter stream, int level, IEnumerable<Block> blocks,
bool showLocals) {
bool showLocals, string nameSuffix = "") {
EmitImplementation(stream, level, writer => {
foreach (var block in blocks) {
block.Emit(writer, level + 1);
}
}, showLocals);
}, showLocals, nameSuffix);
}

public void EmitImplementation(TokenTextWriter stream, int level, Action<TokenTextWriter> printBlocks, bool showLocals)
private void EmitImplementation(TokenTextWriter stream, int level, Action<TokenTextWriter> printBlocks, bool showLocals, string nameSuffix = "")
{
stream.Write(this, level, "implementation ");
EmitAttributes(stream);
stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(this.Name));
stream.Write(this, level, "{0}", TokenTextWriter.SanitizeIdentifier(Name) + nameSuffix);
EmitSignature(stream, false);
stream.WriteLine();

Expand Down
11 changes: 9 additions & 2 deletions Source/Core/AST/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,17 @@ public static Graph<Implementation> BuildCallGraph(CoreOptions options, Program
return callGraph;
}

public static Graph<Block> GraphFromBlocks(List<Block> blocks, bool forward = true)
public static Graph<Block> GraphFromBlocksSubset(IReadOnlyList<Block> blocks, IReadOnlySet<Block> subset = null, bool forward = true)
{
var result = new Graph<Block>();
if (!blocks.Any())
{
return result;
}
void AddEdge(Block a, Block b) {
if (subset != null && (!subset.Contains(a) || !subset.Contains(b))) {
return;
}
Contract.Assert(a != null && b != null);
if (forward) {
result.AddEdge(a, b);
Expand All @@ -514,7 +517,7 @@ void AddEdge(Block a, Block b) {
}
}

result.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
result.AddSource(blocks[0]);
foreach (var block in blocks)
{
if (block.TransferCmd is GotoCmd gtc)
Expand All @@ -525,6 +528,10 @@ void AddEdge(Block a, Block b) {
}
return result;
}

public static Graph<Block> GraphFromBlocks(IReadOnlyList<Block> blocks, bool forward = true) {
return GraphFromBlocksSubset(blocks, null, forward);
}

public static Graph<Block /*!*/> /*!*/ GraphFromImpl(Implementation impl, bool forward = true)
{
Expand Down
15 changes: 12 additions & 3 deletions Source/Core/BoogiePL.atg
Original file line number Diff line number Diff line change
Expand Up @@ -1032,14 +1032,17 @@ TransferCmd<out TransferCmd/*!*/ tc>
= (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd;
Token y; List<IToken>/*!*/ xs;
List<String> ss = new List<String>();
QKeyValue kv = null;
.)
( "goto" (. y = t; .)
Idents<out xs> (. foreach(IToken/*!*/ s in xs){
Contract.Assert(s != null);
ss.Add(s.val); }
tc = new GotoCmd(y, ss);
.)
| "return" (. tc = new ReturnCmd(t); .)
| "return"
{ Attribute<ref kv> }
(. tc = new ReturnCmd(t) { Attributes = kv }; .)
) ";"
.

Expand Down Expand Up @@ -1688,6 +1691,7 @@ SpecBlock<out Block/*!*/ b>
List<IToken>/*!*/ xs;
List<String> ss = new List<String>();
b = dummyBlock;
QKeyValue kv = null;
Expr/*!*/ e;
.)
Ident<out x> ":"
Expand All @@ -1706,8 +1710,13 @@ SpecBlock<out Block/*!*/ b>
ss.Add(s.val); }
b = new Block(x,x.val,cs,new GotoCmd(y,ss));
.)
| "return" Expression<out e>
(. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .)
| "return"
{ Attribute<ref kv> }
Expression<out e>
(. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e) {
Attributes = kv
});
.)
)
";"
.
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/CoreOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace Microsoft.Boogie
public interface CoreOptions : PrintOptions {
public TextWriter OutputWriter { get; }

bool UseBaseNameForFileName { get; }

public enum TypeEncoding
{
Predicates,
Expand Down
31 changes: 31 additions & 0 deletions Source/Core/Generic/ListExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Boogie;

public static class ListExtensions {
public static IReadOnlyList<T> Reversed<T>(this IReadOnlyList<T> list) {
return new ReversedReadOnlyList<T>(list);
}
}

class ReversedReadOnlyList<T> : IReadOnlyList<T> {
private readonly IReadOnlyList<T> inner;

public ReversedReadOnlyList(IReadOnlyList<T> inner) {
this.inner = inner;
}

public IEnumerator<T> GetEnumerator() {
return Enumerable.Range(0, inner.Count).Select(index => this[index]).GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}

public int Count => inner.Count;

public T this[int index] => inner[^(index + 1)];
}
File renamed without changes.
15 changes: 13 additions & 2 deletions Source/Core/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1536,6 +1536,7 @@ void TransferCmd(out TransferCmd/*!*/ tc) {
Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd;
Token y; List<IToken>/*!*/ xs;
List<String> ss = new List<String>();
QKeyValue kv = null;

if (la.kind == 55) {
Get();
Expand All @@ -1548,7 +1549,10 @@ void TransferCmd(out TransferCmd/*!*/ tc) {

} else if (la.kind == 56) {
Get();
tc = new ReturnCmd(t);
while (la.kind == 26) {
Attribute(ref kv);
}
tc = new ReturnCmd(t) { Attributes = kv };
} else SynErr(148);
Expect(10);
}
Expand Down Expand Up @@ -2558,6 +2562,7 @@ void SpecBlock(out Block/*!*/ b) {
List<IToken>/*!*/ xs;
List<String> ss = new List<String>();
b = dummyBlock;
QKeyValue kv = null;
Expr/*!*/ e;

Ident(out x);
Expand All @@ -2583,8 +2588,14 @@ void SpecBlock(out Block/*!*/ b) {

} else if (la.kind == 56) {
Get();
while (la.kind == 26) {
Attribute(ref kv);
}
Expression(out e);
b = new Block(x,x.val,cs,new ReturnExprCmd(t,e));
b = new Block(x,x.val,cs,new ReturnExprCmd(t,e) {
Attributes = kv
});

} else SynErr(174);
Expect(10);
}
Expand Down
3 changes: 1 addition & 2 deletions Source/Core/Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ public string /*!*/

public Token next; // ML 2005-03-11 Tokens are kept in linked list

public static readonly IToken /*!*/
NoToken = new Token();
public static readonly IToken /*!*/ NoToken = new Token();

public Token()
{
Expand Down
15 changes: 8 additions & 7 deletions Source/Core/VariableDependenceAnalyser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -523,14 +523,14 @@ private Dictionary<Block, HashSet<Block>> ComputeGlobalControlDependences()
foreach (var impl in prog.NonInlinedImplementations())
{
var blockGraph = prog.ProcessLoops(options, impl);
localCtrlDeps[impl] = blockGraph.ControlDependence(new Block(prog.tok));
localCtrlDeps[impl] = blockGraph.ControlDependence(new Block(prog.tok, new ReturnCmd(prog.tok)));
foreach (var keyValue in localCtrlDeps[impl])
{
globalCtrlDep.Add(keyValue.Key, keyValue.Value);
}
}

var callGraph = Program.BuildCallGraph(options, prog);
Graph<Implementation> callGraph = Program.BuildCallGraph(options, prog);

// Add inter-procedural control dependence nodes based on calls
foreach (var impl in prog.NonInlinedImplementations())
Expand All @@ -548,7 +548,7 @@ private Dictionary<Block, HashSet<Block>> ComputeGlobalControlDependences()
var indirectCallees = ComputeIndirectCallees(callGraph, directCallee);
foreach (var control in GetControllingBlocks(b, localCtrlDeps[impl]))
{
foreach (var c in indirectCallees.Select(Item => Item.Blocks).SelectMany(Item => Item))
foreach (var c in indirectCallees.Select(item => item.Blocks).SelectMany(Item => Item))
{
globalCtrlDep[control].Add(c);
}
Expand All @@ -562,17 +562,18 @@ private Dictionary<Block, HashSet<Block>> ComputeGlobalControlDependences()

// Finally reverse the dependences

var result = new Dictionary<Block, HashSet<Block>>();
foreach (var keyValue in globalCtrlDep)
Dictionary<Block, HashSet<Block>> result = new Dictionary<Block, HashSet<Block>>();

foreach (var KeyValue in globalCtrlDep)
{
foreach (var v in keyValue.Value)
foreach (var v in KeyValue.Value)
{
if (!result.ContainsKey(v))
{
result[v] = new HashSet<Block>();
}

result[v].Add(keyValue.Key);
result[v].Add(KeyValue.Key);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- Target framework and package configuration -->
<PropertyGroup>
<Version>3.2.5</Version>
<Version>3.3.0</Version>
<TargetFramework>net6.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Authors>Boogie</Authors>
Expand Down
2 changes: 1 addition & 1 deletion Source/ExecutionEngine/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static void PassifyAllImplementations(ExecutionEngineOptions options, ProcessedP

foreach(var implementation in processedProgram.Program.Implementations) {
vcGenerator.PrepareImplementation(new ImplementationRun(implementation, options.OutputWriter),
callback, out _, out _, out _);
callback, out _, out _);
}
}

Expand Down
5 changes: 3 additions & 2 deletions Source/ExecutionEngine/ConsolePrinter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ public virtual void ReportBplError(IToken tok, string message, bool error, TextW
message = $"{category}: {message}";
}

var s = tok != null
? $"{ExecutionEngine.GetFileNameForConsole(Options, tok.filename)}({tok.line},{tok.col}): {message}"
var s = tok != null
? string.Format("{0}({1},{2}): {3}", ExecutionEngine.GetFileNameForConsole(Options, tok.filename), tok.line,
tok.col, message)
: message;

if (error)
Expand Down
Loading

0 comments on commit 25160fa

Please sign in to comment.