Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Civl] fixed pack rule when linear types are involved #807

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Source/Concurrency/LinearDomainCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ private LinearDomainCollector(Program program, CheckingContext checkingContext)
this.visitedTypes = new HashSet<Type>();
}

public static (Dictionary<string, LinearDomain>, Dictionary<Type, LinearDomain>) Collect(Program program, CheckingContext checkingContext)
public static (Dictionary<string, LinearDomain>, Dictionary<Type, LinearDomain>, HashSet<Type>) Collect(Program program, CheckingContext checkingContext)
{
var collector = new LinearDomainCollector(program, checkingContext);
collector.PopulateLinearDomains();
collector.VisitProgram(program);
return (collector.linearDomains, collector.MakeLinearDomains());
return (collector.linearDomains, collector.MakeLinearDomains(), collector.linearTypes);
}

public static LinearKind FindLinearKind(Variable v)
Expand Down
39 changes: 22 additions & 17 deletions Source/Concurrency/LinearTypeChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class LinearTypeChecker : ReadOnlyVisitor
private CivlTypeChecker civlTypeChecker;
private Dictionary<string, LinearDomain> domainNameToLinearDomain;
private Dictionary<Type, LinearDomain> linearTypeToLinearDomain;
private HashSet<Type> linearTypes;
private Dictionary<Absy, HashSet<Variable>> availableLinearVars;

public LinearTypeChecker(CivlTypeChecker civlTypeChecker)
Expand Down Expand Up @@ -220,8 +221,8 @@ private HashSet<Variable> PropagateAvailableLinearVarsAcrossBlock(Block b)
else
{
// pack
var args = ((NAryExpr)rhsExpr).Args.Cast<IdentifierExpr>().Select(arg => arg.Decl)
.Where(v => LinearDomainCollector.FindLinearKind(v) != LinearKind.ORDINARY);
var args = ((NAryExpr)rhsExpr).Args.Where(arg => linearTypes.Contains(arg.Type)).Cast<IdentifierExpr>()
.Select(arg => arg.Decl);
if (args.Any(v => !start.Contains(v)))
{
Error(rhsExpr, "unavailable source for a linear read");
Expand Down Expand Up @@ -487,23 +488,27 @@ public override Cmd VisitAssignCmd(AssignCmd node)
}
rhsVars.Add(rhs.Decl);
}
else if (lhsDomainName == null && rhsExpr is NAryExpr nAryExpr && nAryExpr.Fun is FunctionCall functionCall && functionCall.Func is DatatypeConstructor)
else if (lhsDomainName == null && rhsExpr is NAryExpr { Fun: FunctionCall { Func: DatatypeConstructor } } nAryExpr)
{
// pack
var args = nAryExpr.Args.OfType<IdentifierExpr>();
if (args.Count() < nAryExpr.Args.Count)
nAryExpr.Args.ForEach(arg =>
{
Error(node, $"A source of pack must be a variable");
}
else if (args.Any(arg => LinearDomainCollector.FindDomainName(arg.Decl) != null))
{
Error(node, $"A target of pack must not be a linear variable of name domain");
}
else
{
rhsVars.UnionWith(args.Select(arg => arg.Decl)
.Where(v => LinearDomainCollector.FindLinearKind(v) != LinearKind.ORDINARY));
}
if (linearTypes.Contains(arg.Type))
{
if (arg is IdentifierExpr ie)
{
rhsVars.Add(ie.Decl);
}
else
{
Error(node, $"A source of pack of linear type must be a variable");
}
}
else if (arg is IdentifierExpr ie && LinearDomainCollector.FindDomainName(ie.Decl) != null)
{
Error(node, $"A source of pack must not be a linear variable of name domain");
}
});
}
else
{
Expand Down Expand Up @@ -718,7 +723,7 @@ public override Variable VisitVariable(Variable node)

public void TypeCheck()
{
(this.domainNameToLinearDomain, this.linearTypeToLinearDomain) = LinearDomainCollector.Collect(program, checkingContext);
(this.domainNameToLinearDomain, this.linearTypeToLinearDomain, this.linearTypes) = LinearDomainCollector.Collect(program, checkingContext);
this.availableLinearVars = new Dictionary<Absy, HashSet<Variable>>();
this.VisitProgram(program);
foreach (var absy in this.availableLinearVars.Keys)
Expand Down
7 changes: 7 additions & 0 deletions Test/civl/regression-tests/linear_types.bpl
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,10 @@ atomic action {:layer 1, 2} A10({:linear_in} a: Foo) returns (b: Foo)
Foo(x) := a;
b := Foo(x);
}

datatype Bar { Bar(x: Lval int, y: int) }

atomic action {:layer 1, 2} A11({:linear_in} a: Lval int) returns (b: Bar)
{
b := Bar(a, 3+4);
}
7 changes: 7 additions & 0 deletions Test/civl/regression-tests/linear_types_error.bpl
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,10 @@ atomic action {:layer 1, 2} A13({:linear_in} a: Foo) returns (b: Foo)
var x: Lheap int;
b := Foo(x);
}

datatype Bar { Bar(x: Lval int, y: int) }

atomic action {:layer 1, 2} A14({:linear_in} a: Lval int) returns (b: Bar)
{
b := Bar(Lval(3), 3+4);
}
3 changes: 2 additions & 1 deletion Test/civl/regression-tests/linear_types_error.bpl.expect
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ linear_types_error.bpl(59,4): Error: Primitive assigns to input variable: l'
linear_types_error.bpl(66,0): Error: Output variable b must be available at a return
linear_types_error.bpl(72,14): Error: unavailable source for a linear read
linear_types_error.bpl(78,9): Error: unavailable source for a linear read
15 type checking errors detected in linear_types_error.bpl
linear_types_error.bpl(85,6): Error: A source of pack of linear type must be a variable
16 type checking errors detected in linear_types_error.bpl