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

No flatten for most backends #5528

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
97d81e2
Add patterns/codeSize test
keyboardDrummer May 29, 2024
e77441a
Update codeSize test
keyboardDrummer May 29, 2024
547317f
Split off statement part from SPCG
keyboardDrummer May 29, 2024
55b4cde
Draft of nested match compiler
keyboardDrummer May 30, 2024
b4bc5cf
Save
keyboardDrummer May 30, 2024
f10aa78
Generated code looks good upon visual inspection
keyboardDrummer May 30, 2024
ee9ae6f
Generated code compiles and runs
keyboardDrummer May 30, 2024
069dddb
Move NestedMatch generation to just C#
keyboardDrummer May 30, 2024
da513a0
Attempt at implementation for expressions
keyboardDrummer May 30, 2024
88536c8
Ran formatter
keyboardDrummer May 30, 2024
f13be6e
Fixes
keyboardDrummer May 30, 2024
a61d607
Update C# code generator zo it also uses custom generation for nested…
keyboardDrummer May 30, 2024
846ad62
Regen GeneratedFromDafny code
keyboardDrummer May 30, 2024
85c1b20
Revert "Regen GeneratedFromDafny code"
keyboardDrummer May 30, 2024
3660a37
Fix gen
keyboardDrummer May 30, 2024
26000a5
Fixes for generics
keyboardDrummer May 30, 2024
2805584
Update generated files
keyboardDrummer May 30, 2024
09f39f8
Merge branch 'master' into noFlattenForCSharp
keyboardDrummer May 30, 2024
82a5d71
Fix bug related to disjoint patterns
keyboardDrummer May 31, 2024
c32be6f
Merge branch 'noFlattenForCSharp' of github.com:keyboardDrummer/dafny…
keyboardDrummer May 31, 2024
861cee7
Merge remote-tracking branch 'origin/master' into noFlattenForCSharp
keyboardDrummer May 31, 2024
1e25d7b
Fix literal pattern bug
keyboardDrummer May 31, 2024
6791e43
Remove DatatypeWrapperEraser.IsErasableDatatypeWrapper check
keyboardDrummer May 31, 2024
eedcf47
Ran formatter
keyboardDrummer May 31, 2024
6f981ab
Fix bug in disjunctive assignments
keyboardDrummer May 31, 2024
0bd8c0d
Merge branch 'master' into noFlattenForCSharp
keyboardDrummer May 31, 2024
903f2bf
Trigger CI
keyboardDrummer May 31, 2024
5d9dc07
Merge branch 'noFlattenForCSharp' of github.com:keyboardDrummer/dafny…
keyboardDrummer May 31, 2024
9477c6f
Fixes
keyboardDrummer Jun 1, 2024
b919fa8
Refactoring
keyboardDrummer Jun 1, 2024
c6de95b
Add force integration tests code
keyboardDrummer Jun 3, 2024
0672492
Merge branch 'master' into noFlattenForCSharp
keyboardDrummer Jun 4, 2024
3c86dd7
Convert if else chains to switch
keyboardDrummer Jun 4, 2024
e45420a
Merge commit 'a748799eef1d7~1' into noFlattenForCSharp
keyboardDrummer Jun 5, 2024
b8de307
Merge commit 'a748799eef1d7' into noFlattenForCSharp
keyboardDrummer Jun 5, 2024
f97bf09
Merge remote-tracking branch 'origin/master' into noFlattenForCSharp
keyboardDrummer Jun 5, 2024
75bb47e
Ran formatter
keyboardDrummer Jun 5, 2024
e1bb707
Refactoring
keyboardDrummer Jun 5, 2024
dbcb4a4
Further refactoring
keyboardDrummer Jun 5, 2024
420a13b
Further refactoring
keyboardDrummer Jun 5, 2024
5f860c9
Attempt at using nested matches for all backends
keyboardDrummer Jun 5, 2024
808d090
Use flattened matches for DafnyCodeGenerator
keyboardDrummer Jun 5, 2024
126344a
Reintroduce flattening for Java
keyboardDrummer Jun 5, 2024
a1011f7
Fixes
keyboardDrummer Jun 5, 2024
387b35f
Remove codeSize test
keyboardDrummer Jun 5, 2024
49e0c55
Update expect files
keyboardDrummer Jun 5, 2024
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
Prev Previous commit
Next Next commit
Attempt at using nested matches for all backends
  • Loading branch information
keyboardDrummer committed Jun 5, 2024
commit 5f860c9482f2c94e9a384d5825fcc1adc56856cc
179 changes: 0 additions & 179 deletions Source/DafnyCore/Backends/CSharp/CsharpCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3523,184 +3523,5 @@ public class CodeCoverage {
}
}");
}

protected override void EmitNestedMatchExpr(NestedMatchExpr match, bool inLetExprBody, ConcreteSyntaxTree output, ConcreteSyntaxTree wStmts) {
var lambdaBody = EmitAppliedLambda(output, wStmts, match.Tok, match.Type);
TrOptNestedMatchExpr(match, match.Type, lambdaBody, wStmts, inLetExprBody, null);
}

private ConcreteSyntaxTree EmitAppliedLambda(ConcreteSyntaxTree output, ConcreteSyntaxTree wStmts,
IToken token, Type resultType) {
EmitLambdaApply(output, out var lambdaApplyTarget, out _);
return CreateLambda(new List<Type>(), token, new List<string>(), resultType, lambdaApplyTarget, wStmts);
}

protected override void TrOptNestedMatchExpr(NestedMatchExpr match, Type resultType, ConcreteSyntaxTree wr,
ConcreteSyntaxTree wStmts, bool inLetExprBody, IVariable accumulatorVar) {

wStmts = wr.Fork();

EmitNestedMatchGeneric(match, (caseIndex, caseBody) => {
var myCase = match.Cases[caseIndex];
TrExprOpt(myCase.Body, myCase.Body.Type, caseBody, wStmts, inLetExprBody: true, accumulatorVar: null);
}, wr, true);
}

protected override void EmitNestedMatchStmt(NestedMatchStmt match, ConcreteSyntaxTree writer) {
EmitNestedMatchGeneric(match, (caseIndex, caseBody) => {
TrStmtList(match.Cases[caseIndex].Body, caseBody);
}, writer, false);
}

/// <summary>
///
/// match a
/// case X(Y(b),Z(W(c)) => body1
/// case r => body2
///
/// var unmatched = true;
/// if (unmatched && a is X) {
/// var x1 = ((X)a).1;
/// if (x1 is Y) {
/// var b = ((Y)x1).1;
///
/// var x2 = ((X)a).2;
/// if (x2 is Z) {
/// var x4 = ((Z)x2).1;
/// if (x4 is W) {
/// var c = ((W)x4).1;
/// body1;
/// }
/// }
/// }
/// }
/// if (unmatched) {
/// var r = a;
/// body2;
/// }
///
/// </summary>
private void EmitNestedMatchGeneric(INestedMatch match, Action<int, ConcreteSyntaxTree> emitBody,
ConcreteSyntaxTree output, bool bodyExpected) {
if (match.Cases.Count == 0) {
if (bodyExpected) {
// the verifier would have proved we never get here; still, we need some code that will compile
EmitAbsurd(null, output);
}
} else {
string sourceName = ProtectedFreshId("_source");
DeclareLocalVar(sourceName, match.Source.Type, match.Source.tok, match.Source, false, output);

string unmatched = ProtectedFreshId("unmatched");
DeclareLocalVar(unmatched, Type.Bool, match.Source.Tok, Expression.CreateBoolLiteral(match.Source.Tok, true), false, output);

var sourceType = match.Source.Type.NormalizeExpand();
for (var index = 0; index < match.Cases.Count; index++) {
var myCase = match.Cases[index];
var lastCase = index == match.Cases.Count - 1;
var result = EmitIf(out var guardWriter, false, output);
guardWriter.Write(unmatched);
var innerWriter = EmitNestedMatchCaseConditions(sourceName, sourceType, myCase.Pat, result, lastCase);
Coverage.Instrument(myCase.Tok, "case body", innerWriter);
EmitAssignment(unmatched, Type.Bool, False, Type.Bool, innerWriter);

emitBody(index, innerWriter);
}

if (bodyExpected) {
EmitAbsurd(null, output);
}
}
}

private ConcreteSyntaxTree EmitNestedMatchCaseConditions(string sourceName,
Type sourceType,
ExtendedPattern pattern, ConcreteSyntaxTree writer, bool lastCase) {

var litExpression = MatchFlattener.GetLiteralExpressionFromPattern(pattern);
if (litExpression != null) {
var thenWriter = EmitIf(out var guardWriter, false, writer);
CompileBinOp(BinaryExpr.ResolvedOpcode.EqCommon, sourceType, litExpression.Type, pattern.Tok, Type.Bool,
out var opString, out var preOpString, out var postOpString, out var callString, out var staticCallString,
out _, out _, out _, out _,
writer);
var right = new ConcreteSyntaxTree();
EmitExpr(litExpression, false, right, writer);
EmitBinaryExprUsingConcreteSyntax(guardWriter, Type.Bool, preOpString, opString, new LineSegment(sourceName), right, callString, staticCallString, postOpString);
writer = thenWriter;
} else if (pattern is IdPattern idPattern) {
if (idPattern.BoundVar != null) {
var boundVar = idPattern.BoundVar;
var valueWriter = DeclareLocalVar(IdName(boundVar), boundVar.Type, idPattern.Tok, writer);
valueWriter.Write(sourceName);
return writer;
} else {
writer = EmitNestedMatchStmtCaseConstructor(sourceName, sourceType, idPattern, writer, lastCase);
}

} else if (pattern is DisjunctivePattern disjunctivePattern) {
string disjunctiveMatch = ProtectedFreshId("disjunctiveMatch");
DeclareLocalVar(disjunctiveMatch, Type.Bool, disjunctivePattern.Tok, Expression.CreateBoolLiteral(disjunctivePattern.Tok, false), false, writer);
foreach (var alternative in disjunctivePattern.Alternatives) {
var alternativeWriter = EmitNestedMatchCaseConditions(sourceName, sourceType, alternative, writer, lastCase);
EmitAssignment(disjunctiveMatch, Type.Bool, True, Type.Bool, alternativeWriter);
}
writer = EmitIf(out var guardWriter, false, writer);
guardWriter.Write(disjunctiveMatch);
} else {
throw new Exception();
}

return writer;
}

private ConcreteSyntaxTree EmitNestedMatchStmtCaseConstructor(string sourceName, Type sourceType,
IdPattern idPattern,
ConcreteSyntaxTree result, bool lastCase) {
var ctor = idPattern.Ctor;

if (!lastCase && ctor.EnclosingDatatype.Ctors.Count != 1) {
result = EmitIf(out var guardWriter, false, result);
EmitConstructorCheck(sourceName, ctor, guardWriter);
}

var userDefinedType = (UserDefinedType)sourceType.NormalizeExpand();

var typeSubstMap =
TypeParameter.SubstitutionMap(userDefinedType.ResolvedClass.TypeArgs, userDefinedType.TypeArgs);
int nonGhostIndex = 0; // number of processed non-ghost arguments
for (int index = 0; index < ctor.Formals.Count; index++) {
var arg = ctor.Formals[index];

if (arg.IsGhost) {
continue;
}

var type = arg.Type.Subst(typeSubstMap);
// ((Dt_Ctor0)source._D).a0;
var destructor = new ConcreteSyntaxTree();
EmitDestructor(wr => EmitIdentifier(sourceName, wr), arg, nonGhostIndex, ctor,
() => SelectNonGhost(userDefinedType.ResolvedClass, userDefinedType.TypeArgs), type, destructor);

if (idPattern.Arguments != null) {
string newSourceName;
var childPattern = idPattern.Arguments[index];
if (childPattern is IdPattern { BoundVar: not null } childIdPattern) {
var boundVar = childIdPattern.BoundVar;
newSourceName = IdName(boundVar);
var valueWriter = DeclareLocalVar(newSourceName, boundVar.Type, idPattern.Tok, result);
valueWriter.Append(destructor);
} else {
newSourceName = ProtectedFreshId(arg.CompileName);
var valueWriter = DeclareLocalVar(newSourceName, type, idPattern.Tok, result);
valueWriter.Append(destructor);
result = EmitNestedMatchCaseConditions(newSourceName, type, childPattern, result, lastCase);
}
}
nonGhostIndex++;
}

return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -707,11 +707,26 @@ public abstract partial class SinglePassCodeGenerator {
EmitExpr(e.Source, inLetExprBody, wArg, wStmts);
}

protected virtual void EmitNestedMatchExpr(NestedMatchExpr match, bool inLetExprBody, ConcreteSyntaxTree wr, ConcreteSyntaxTree wStmts) {
EmitExpr(match.Flattened, inLetExprBody, wr, wStmts);
protected virtual void EmitNestedMatchExpr(NestedMatchExpr match, bool inLetExprBody, ConcreteSyntaxTree output, ConcreteSyntaxTree wStmts) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the changes in this file start.

var lambdaBody = EmitAppliedLambda(output, wStmts, match.Tok, match.Type);
TrOptNestedMatchExpr(match, match.Type, lambdaBody, wStmts, inLetExprBody, null);
}
protected virtual void TrOptNestedMatchExpr(NestedMatchExpr nestedMatchExpr, Type resultType, ConcreteSyntaxTree wr, ConcreteSyntaxTree wStmts, bool inLetExprBody, IVariable accumulatorVar) {
TrExprOpt(nestedMatchExpr.Flattened, resultType, wr, wStmts, inLetExprBody, accumulatorVar);

protected virtual void TrOptNestedMatchExpr(NestedMatchExpr match, Type resultType, ConcreteSyntaxTree wr,
ConcreteSyntaxTree wStmts, bool inLetExprBody, IVariable accumulatorVar) {

wStmts = wr.Fork();

EmitNestedMatchGeneric(match, (caseIndex, caseBody) => {
var myCase = match.Cases[caseIndex];
TrExprOpt(myCase.Body, myCase.Body.Type, caseBody, wStmts, inLetExprBody: true, accumulatorVar: null);
}, wr, true);
}

private ConcreteSyntaxTree EmitAppliedLambda(ConcreteSyntaxTree output, ConcreteSyntaxTree wStmts,
IToken token, Type resultType) {
EmitLambdaApply(output, out var lambdaApplyTarget, out _);
return CreateLambda(new List<Type>(), token, new List<string>(), resultType, lambdaApplyTarget, wStmts);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,160 @@ public abstract partial class SinglePassCodeGenerator {
}

protected virtual void EmitNestedMatchStmt(NestedMatchStmt match, ConcreteSyntaxTree writer) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the changes in this file start.

TrStmt(match.Flattened, writer);
EmitNestedMatchGeneric(match, (caseIndex, caseBody) => {
TrStmtList(match.Cases[caseIndex].Body, caseBody);
}, writer, false);
}

/// <summary>
///
/// match a
/// case X(Y(b),Z(W(c)) => body1
/// case r => body2
///
/// var unmatched = true;
/// if (unmatched && a is X) {
/// var x1 = ((X)a).1;
/// if (x1 is Y) {
/// var b = ((Y)x1).1;
///
/// var x2 = ((X)a).2;
/// if (x2 is Z) {
/// var x4 = ((Z)x2).1;
/// if (x4 is W) {
/// var c = ((W)x4).1;
/// body1;
/// }
/// }
/// }
/// }
/// if (unmatched) {
/// var r = a;
/// body2;
/// }
///
/// </summary>
private void EmitNestedMatchGeneric(INestedMatch match, Action<int, ConcreteSyntaxTree> emitBody,
ConcreteSyntaxTree output, bool bodyExpected) {
if (match.Cases.Count == 0) {
if (bodyExpected) {
// the verifier would have proved we never get here; still, we need some code that will compile
EmitAbsurd(null, output);
}
} else {
string sourceName = ProtectedFreshId("_source");
DeclareLocalVar(sourceName, match.Source.Type, match.Source.tok, match.Source, false, output);

string unmatched = ProtectedFreshId("unmatched");
DeclareLocalVar(unmatched, Type.Bool, match.Source.Tok, Expression.CreateBoolLiteral(match.Source.Tok, true), false, output);

var sourceType = match.Source.Type.NormalizeExpand();
for (var index = 0; index < match.Cases.Count; index++) {
var myCase = match.Cases[index];
var lastCase = index == match.Cases.Count - 1;
var result = EmitIf(out var guardWriter, false, output);
guardWriter.Write(unmatched);
var innerWriter = EmitNestedMatchCaseConditions(sourceName, sourceType, myCase.Pat, result, lastCase);
Coverage.Instrument(myCase.Tok, "case body", innerWriter);
EmitAssignment(unmatched, Type.Bool, False, Type.Bool, innerWriter);

emitBody(index, innerWriter);
}

if (bodyExpected) {
EmitAbsurd(null, output);
}
}
}

private ConcreteSyntaxTree EmitNestedMatchCaseConditions(string sourceName,
Type sourceType,
ExtendedPattern pattern, ConcreteSyntaxTree writer, bool lastCase) {

var litExpression = MatchFlattener.GetLiteralExpressionFromPattern(pattern);
if (litExpression != null) {
var thenWriter = EmitIf(out var guardWriter, false, writer);
CompileBinOp(BinaryExpr.ResolvedOpcode.EqCommon, sourceType, litExpression.Type, pattern.Tok, Type.Bool,
out var opString, out var preOpString, out var postOpString, out var callString, out var staticCallString,
out _, out _, out _, out _,
writer);
var right = new ConcreteSyntaxTree();
EmitExpr(litExpression, false, right, writer);
EmitBinaryExprUsingConcreteSyntax(guardWriter, Type.Bool, preOpString, opString, new LineSegment(sourceName), right, callString, staticCallString, postOpString);
writer = thenWriter;
} else if (pattern is IdPattern idPattern) {
if (idPattern.BoundVar != null) {
var boundVar = idPattern.BoundVar;
var valueWriter = DeclareLocalVar(IdName(boundVar), boundVar.Type, idPattern.Tok, writer);
valueWriter.Write(sourceName);
return writer;
} else {
writer = EmitNestedMatchStmtCaseConstructor(sourceName, sourceType, idPattern, writer, lastCase);
}

} else if (pattern is DisjunctivePattern disjunctivePattern) {
string disjunctiveMatch = ProtectedFreshId("disjunctiveMatch");
DeclareLocalVar(disjunctiveMatch, Type.Bool, disjunctivePattern.Tok, Expression.CreateBoolLiteral(disjunctivePattern.Tok, false), false, writer);
foreach (var alternative in disjunctivePattern.Alternatives) {
var alternativeWriter = EmitNestedMatchCaseConditions(sourceName, sourceType, alternative, writer, lastCase);
EmitAssignment(disjunctiveMatch, Type.Bool, True, Type.Bool, alternativeWriter);
}
writer = EmitIf(out var guardWriter, false, writer);
guardWriter.Write(disjunctiveMatch);
} else {
throw new Exception();
}

return writer;
}

private ConcreteSyntaxTree EmitNestedMatchStmtCaseConstructor(string sourceName, Type sourceType,
IdPattern idPattern,
ConcreteSyntaxTree result, bool lastCase) {
var ctor = idPattern.Ctor;

if (!lastCase && ctor.EnclosingDatatype.Ctors.Count != 1) {
result = EmitIf(out var guardWriter, false, result);
EmitConstructorCheck(sourceName, ctor, guardWriter);
}

var userDefinedType = (UserDefinedType)sourceType.NormalizeExpand();

var typeSubstMap =
TypeParameter.SubstitutionMap(userDefinedType.ResolvedClass.TypeArgs, userDefinedType.TypeArgs);
int nonGhostIndex = 0; // number of processed non-ghost arguments
for (int index = 0; index < ctor.Formals.Count; index++) {
var arg = ctor.Formals[index];

if (arg.IsGhost) {
continue;
}

var type = arg.Type.Subst(typeSubstMap);
// ((Dt_Ctor0)source._D).a0;
var destructor = new ConcreteSyntaxTree();
EmitDestructor(wr => EmitIdentifier(sourceName, wr), arg, nonGhostIndex, ctor,
() => SelectNonGhost(userDefinedType.ResolvedClass, userDefinedType.TypeArgs), type, destructor);

if (idPattern.Arguments != null) {
string newSourceName;
var childPattern = idPattern.Arguments[index];
if (childPattern is IdPattern { BoundVar: not null } childIdPattern) {
var boundVar = childIdPattern.BoundVar;
newSourceName = IdName(boundVar);
var valueWriter = DeclareLocalVar(newSourceName, boundVar.Type, idPattern.Tok, result);
valueWriter.Append(destructor);
} else {
newSourceName = ProtectedFreshId(arg.CompileName);
var valueWriter = DeclareLocalVar(newSourceName, type, idPattern.Tok, result);
valueWriter.Append(destructor);
result = EmitNestedMatchCaseConditions(newSourceName, type, childPattern, result, lastCase);
}
}
nonGhostIndex++;
}

return result;
}
}
}