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

fix: Set/forall comprehensions with subtyping for issue #697 #1522

Merged
merged 38 commits into from
Dec 2, 2021
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3268e9b
Added failing tests.
MikaelMayer Oct 19, 2021
76b2708
Added failing tests for exists and map
MikaelMayer Oct 19, 2021
d3e1d9b
Renamed tests for consistency
MikaelMayer Oct 19, 2021
83075e6
Changed compilation parameter for tests
MikaelMayer Oct 21, 2021
0e8cdf8
Better test files
MikaelMayer Oct 25, 2021
2c9aead
WIP: Ensuring subset onstraints are compiled
MikaelMayer Oct 25, 2021
da35915
WIP fixing interfaces
MikaelMayer Oct 25, 2021
4724c1b
Refactored the code to inject guards for set and map expressions
MikaelMayer Oct 26, 2021
1076022
Fixed soundness, but now it does not allow non-compilable guards.
MikaelMayer Nov 2, 2021
f784d0a
Merge remote-tracking branch 'origin/master' into fix-697
MikaelMayer Nov 2, 2021
e4d1938
Support for ghost in subset constraints if not used in comprehensions
MikaelMayer Nov 2, 2021
94b1d55
Merge remote-tracking branch 'origin/master' into fix-697
MikaelMayer Nov 3, 2021
c9a8e04
Fixed the merge
MikaelMayer Nov 3, 2021
d7ef9e5
Merge branch 'master' into fix-697
MikaelMayer Nov 5, 2021
c6d47e9
Fix should not apply for lambdas, which are special "comprehensions"
MikaelMayer Nov 5, 2021
8bb4746
Error message only in non-ghost context.
MikaelMayer Nov 5, 2021
856e38c
Check if the constraint is compilable if not already done.
MikaelMayer Nov 5, 2021
f539211
Added the return expression if no subset type in forall.
MikaelMayer Nov 9, 2021
8e653a0
Merge branch 'master' into fix-697
MikaelMayer Nov 9, 2021
a3f8a6e
fix: tolerate traversing sub-expressions when checking compilability.
MikaelMayer Nov 9, 2021
e52858a
Merge branch 'fix-697' of https://github.com/dafny-lang/dafny into fi…
MikaelMayer Nov 9, 2021
8516e32
Default value for IsGhost for top-level declarations.
MikaelMayer Nov 9, 2021
447a93d
Enhancement: MissingBounds works even if bounds were never defined.
MikaelMayer Nov 10, 2021
fcc4828
Merge branch 'master' into fix-697
MikaelMayer Nov 10, 2021
8793edb
Newest way to verify subset constraint
MikaelMayer Nov 15, 2021
749b4b1
Moved subset constraint checker to the right place.
MikaelMayer Nov 15, 2021
4821353
Merge remote-tracking branch 'origin/master' into fix-697
MikaelMayer Nov 15, 2021
d69097a
Merge branch 'fix-697' of https://github.com/dafny-lang/dafny into fi…
MikaelMayer Nov 15, 2021
7e13479
Verification if parameters are null.
MikaelMayer Nov 15, 2021
7d836e8
Fixed ordering of boolean expressions.
MikaelMayer Nov 16, 2021
49c57f2
Merge branch 'master' into fix-697
MikaelMayer Nov 16, 2021
f9eb690
Emitted a block in the else statement for Go.
MikaelMayer Nov 16, 2021
d377748
Verification step should not apply to lambdas
MikaelMayer Nov 16, 2021
4ccb1fc
Reverted the IsGhost for newtypes and subset types since not used any…
MikaelMayer Nov 16, 2021
3ac28b7
- Reverted to old var = (subtype) assignment
MikaelMayer Nov 22, 2021
b8e9e49
Merge branch 'master' into fix-697
MikaelMayer Nov 22, 2021
e7efc3b
Added the test for integers
MikaelMayer Nov 24, 2021
4eed576
Merge branch 'master' into fix-697
RustanLeino Dec 1, 2021
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
6 changes: 4 additions & 2 deletions Source/Dafny/AST/DafnyAst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5573,7 +5573,7 @@ public TypeParameter.EqualitySupportValue EqualitySupport {
FreshIdGenerator RedirectingTypeDecl.IdGenerator { get { return IdGenerator; } }

bool ICodeContext.IsGhost {
get { throw new NotSupportedException(); } // if .IsGhost is needed, the object should always be wrapped in an CodeContextWrapper
get { return false; }
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
}
List<TypeParameter> ICodeContext.TypeArgs { get { return new List<TypeParameter>(); } }
List<Formal> ICodeContext.Ins { get { return new List<Formal>(); } }
Expand Down Expand Up @@ -5656,7 +5656,7 @@ public Type RhsWithArgumentIgnoringScope(List<Type> typeArgs) {
FreshIdGenerator RedirectingTypeDecl.IdGenerator { get { return IdGenerator; } }

bool ICodeContext.IsGhost {
get { throw new NotSupportedException(); } // if .IsGhost is needed, the object should always be wrapped in an CodeContextWrapper
get { return false; }
}
List<TypeParameter> ICodeContext.TypeArgs { get { return TypeArgs; } }
List<Formal> ICodeContext.Ins { get { return new List<Formal>(); } }
Expand Down Expand Up @@ -5703,6 +5703,8 @@ public class SubsetTypeDecl : TypeSynonymDecl, RedirectingTypeDecl {
public enum WKind { CompiledZero, Compiled, Ghost, OptOut, Special }
public readonly SubsetTypeDecl.WKind WitnessKind;
public readonly Expression/*?*/ Witness; // non-null iff WitnessKind is Compiled or Ghost
public bool ConstraintIsCompilable = false; // Will be resolved later.
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
public bool CheckedIfConstraintIsCompilable = false; // Will be resolved later.
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
public SubsetTypeDecl(IToken tok, string name, TypeParameter.TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs, ModuleDefinition module,
BoundVar id, Expression constraint, WKind witnessKind, Expression witness,
Attributes attributes)
Expand Down
82 changes: 66 additions & 16 deletions Source/Dafny/Compilers/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4610,14 +4610,13 @@ void writeObj(ConcreteSyntaxTree w) {
wBody.Write(", {0}, ", expr is ForallExpr ? "true" : "false");
var native = AsNativeType(e.BoundVars[i].Type);
ConcreteSyntaxTree newWBody = CreateLambda(new List<Type> { bv.Type }, e.tok, new List<string> { IdName(bv) }, Type.Bool, wBody, untyped: true);
newWBody = EmitReturnExpr(newWBody);
newWBody = MaybeInjectSubsetConstraint(newWBody, inLetExprBody, e.BoundVars[i], e, true, e is ForallExpr);
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
wBody.Write(')');
wBody = newWBody;
}
TrExpr(logicalBody, wBody, true);

} else if (expr is SetComprehension) {
var e = (SetComprehension)expr;
} else if (expr is SetComprehension setComprehension) {
// For "set i,j,k,l | R(i,j,k,l) :: Term(i,j,k,l)" where the term has type "G", emit something like:
// ((System.Func<Set<G>>)(() => {
// var _coll = new List<G>();
Expand All @@ -4634,29 +4633,33 @@ void writeObj(ConcreteSyntaxTree w) {
// }
// return Dafny.Set<G>.FromCollection(_coll);
// }))()
wr = CaptureFreeVariables(e, true, out var su, inLetExprBody, wr);
e = (SetComprehension)su.Substitute(e);
wr = CaptureFreeVariables(setComprehension, true, out var su, inLetExprBody, wr);
setComprehension = (SetComprehension)su.Substitute(setComprehension);

Contract.Assert(e.Bounds != null); // the resolver would have insisted on finding bounds
Contract.Assert(setComprehension.Bounds != null); // the resolver would have insisted on finding bounds
var collectionName = idGenerator.FreshId("_coll");
var bwr = CreateIIFE0(e.Type.AsSetType, e.tok, wr);
var bwr = CreateIIFE0(setComprehension.Type.AsSetType, setComprehension.tok, wr);
wr = bwr;
EmitSetBuilder_New(wr, e, collectionName);
var n = e.BoundVars.Count;
Contract.Assert(e.Bounds.Count == n);
for (var i = 0; i < n; i++) {
var bound = e.Bounds[i];
var bv = e.BoundVars[i];
EmitSetBuilder_New(wr, setComprehension, collectionName);
var n = setComprehension.BoundVars.Count;
Contract.Assert(setComprehension.Bounds.Count == n);
int i;
for (i = 0; i < n; i++) {
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
var bound = setComprehension.Bounds[i];
var bv = setComprehension.BoundVars[i];
ConcreteSyntaxTree collectionWriter;
var tmpVar = idGenerator.FreshId("_compr_");
wr = CreateForeachLoop(tmpVar, GetCollectionEnumerationType(bound, bv), IdName(bv), bv.Type, true, bv.tok, out collectionWriter, wr);
// var s = {List(Cell(1)), List(Cell(2), Cell(4)), List(Cell(2), Cell(3))};
// set x: List<EvenCell> | x in s
wr = MaybeInjectSubsetConstraint(wr, inLetExprBody, bv, setComprehension);
CompileCollection(bound, bv, inLetExprBody, true, null, collectionWriter);
}
ConcreteSyntaxTree guardWriter;
var thn = EmitIf(out guardWriter, false, wr);
TrExpr(e.Range, guardWriter, inLetExprBody);
EmitSetBuilder_Add(e.Type.AsSetType, collectionName, e.Term, inLetExprBody, thn);
var s = GetCollectionBuilder_Build(e.Type.AsSetType, e.tok, collectionName, wr);
TrExpr(setComprehension.Range, guardWriter, inLetExprBody);
EmitSetBuilder_Add(setComprehension.Type.AsSetType, collectionName, setComprehension.Term, inLetExprBody, thn);
var s = GetCollectionBuilder_Build(setComprehension.Type.AsSetType, setComprehension.tok, collectionName, wr);
EmitReturnExpr(s, bwr);

} else if (expr is MapComprehension) {
Expand Down Expand Up @@ -4695,6 +4698,7 @@ void writeObj(ConcreteSyntaxTree w) {
ConcreteSyntaxTree collectionWriter;
var tmpVar = idGenerator.FreshId("_compr_");
wr = CreateForeachLoop(tmpVar, GetCollectionEnumerationType(bound, bv), IdName(bv), bv.Type, true, bv.tok, out collectionWriter, wr);
wr = MaybeInjectSubsetConstraint(wr, inLetExprBody, bv, e);
CompileCollection(bound, bv, inLetExprBody, true, null, collectionWriter);
}
ConcreteSyntaxTree guardWriter;
Expand Down Expand Up @@ -4736,6 +4740,52 @@ void writeObj(ConcreteSyntaxTree w) {
}
}

private ConcreteSyntaxTree MaybeInjectSubsetConstraint(ConcreteSyntaxTree wr, bool inLetExprBody, BoundVar bv,
Expression e, bool isReturning = false, bool elseReturnValue = false) {
int i;
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
if (bv.Type is UserDefinedType
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
{
TypeArgs: var typeArgs,
ResolvedClass:
var subsetTypeDecl and
SubsetTypeDecl
MikaelMayer marked this conversation as resolved.
Show resolved Hide resolved
{
TypeArgs: var typeParametersArgs,
Var: var var,
ConstraintIsCompilable: true,
Constraint: var constraint
}
}) {
var bvIdentifier = new IdentifierExpr(e.tok, bv);
var typeParameters = new Dictionary<TypeParameter, Type> { };
for (i = 0; i < typeParametersArgs.Count(); i++) {
typeParameters[typeParametersArgs[i]] = typeArgs[i];
}
var subContract = new Substituter(null,
new Dictionary<IVariable, Expression>()
{
{var, bvIdentifier}
},
new Dictionary<TypeParameter, Type>(
typeParameters
)
);
var constraintInContext = subContract.Substitute(constraint);
var thenWriter = EmitIf(out var guardWriter, isReturning, wr);
TrExpr(constraintInContext, guardWriter, inLetExprBody);
if (isReturning) {
wr = EmitReturnExpr(wr);
TrExpr(new LiteralExpr(e.tok, elseReturnValue), wr, inLetExprBody);
thenWriter = EmitReturnExpr(thenWriter);
}
wr = thenWriter;
} else if (isReturning) {
wr = EmitReturnExpr(wr);
}

return wr;
}

protected ConcreteSyntaxTree CaptureFreeVariables(Expression expr, bool captureOnlyAsRequiredByTargetLanguage, out Substituter su, bool inLetExprBody, ConcreteSyntaxTree wr) {
if (captureOnlyAsRequiredByTargetLanguage && TargetLambdaCanUseEnclosingLocals) {
// nothing to do
Expand Down
Loading