Skip to content

Commit 0f25bcc

Browse files
Allow attributes on CaseExpression (#1298)
* Allow attributes on CaseExpression * resolve attributes on caseExpr * fixed rprint * minor comment * attribute checks updated Co-authored-by: Jatin Arora <[email protected]>
1 parent f02462d commit 0f25bcc

File tree

8 files changed

+78
-34
lines changed

8 files changed

+78
-34
lines changed

Source/Dafny/Cloner.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,12 +478,12 @@ public virtual Expression CloneExpr(Expression expr) {
478478
public MatchCaseExpr CloneMatchCaseExpr(MatchCaseExpr c) {
479479
Contract.Requires(c != null);
480480
Contract.Requires(c.Arguments != null);
481-
return new MatchCaseExpr(Tok(c.tok), c.Ctor, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body));
481+
return new MatchCaseExpr(Tok(c.tok), c.Ctor, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body), CloneAttributes(c.Attributes));
482482
}
483483

484484
public NestedMatchCaseExpr CloneNestedMatchCaseExpr(NestedMatchCaseExpr c) {
485485
Contract.Requires(c != null);
486-
return new NestedMatchCaseExpr(Tok(c.Tok), CloneExtendedPattern(c.Pat), CloneExpr(c.Body));
486+
return new NestedMatchCaseExpr(Tok(c.Tok), CloneExtendedPattern(c.Pat), CloneExpr(c.Body), CloneAttributes(c.Attributes));
487487
}
488488

489489
public virtual Expression CloneApplySuffix(ApplySuffix e) {
@@ -902,7 +902,7 @@ public override ModuleDefinition CloneModuleDefinition(ModuleDefinition m, strin
902902
if (def == null) {
903903
continue;
904904
}
905-
905+
906906
if (!declmap.ContainsKey(def)) {
907907
declmap.Add(def, new List<AliasModuleDecl>());
908908
sigmap.Add(def, new ModuleSignature());

Source/Dafny/Dafny.atg

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4113,11 +4113,13 @@ CaseExpression<out NestedMatchCaseExpr c, bool allowLemma, bool allowLambda, boo
41134113
= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ x;
41144114
ExtendedPattern/*!*/ pat = null;
41154115
Expression/*!*/ body;
4116+
Attributes attrs = null;
41164117
.)
41174118
"case" (. x = t; .)
4119+
{ Attribute<ref attrs> }
41184120
ExtendedPattern<out pat> (. .)
41194121
"=>"
4120-
Expression<out body, allowLemma, allowLambda, allowBitwiseOps> (. c = new NestedMatchCaseExpr(x, pat, body); .)
4122+
Expression<out body, allowLemma, allowLambda, allowBitwiseOps> (. c = new NestedMatchCaseExpr(x, pat, body, attrs); .)
41214123
.
41224124

41234125
/*------------------------------------------------------------------------*/

Source/Dafny/DafnyAst.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9558,7 +9558,7 @@ public static MatchCaseExpr CreateMatchCase(MatchCaseExpr old_case, Expression n
95589558
var newVars = old_case.Arguments.ConvertAll(cloner.CloneBoundVar);
95599559
new_body = VarSubstituter(old_case.Arguments.ConvertAll<NonglobalVariable>(x=>(NonglobalVariable)x), newVars, new_body);
95609560

9561-
var new_case = new MatchCaseExpr(old_case.tok, old_case.Ctor, newVars, new_body);
9561+
var new_case = new MatchCaseExpr(old_case.tok, old_case.Ctor, newVars, new_body, old_case.Attributes);
95629562

95639563
new_case.Ctor = old_case.Ctor; // resolve here
95649564
return new_case;
@@ -12132,18 +12132,20 @@ public MatchCase(IToken tok, DatatypeCtor ctor, [Captured] List<BoundVar> argume
1213212132
public class MatchCaseExpr : MatchCase
1213312133
{
1213412134
private Expression body;
12135+
public Attributes Attributes;
1213512136
[ContractInvariantMethod]
1213612137
void ObjectInvariant() {
1213712138
Contract.Invariant(body != null);
1213812139
}
1213912140

12140-
public MatchCaseExpr(IToken tok, DatatypeCtor ctor, [Captured] List<BoundVar> arguments, Expression body)
12141+
public MatchCaseExpr(IToken tok, DatatypeCtor ctor, [Captured] List<BoundVar> arguments, Expression body, Attributes attrs = null)
1214112142
: base(tok, ctor, arguments) {
1214212143
Contract.Requires(tok != null);
1214312144
Contract.Requires(ctor != null);
1214412145
Contract.Requires(cce.NonNullElements(arguments));
1214512146
Contract.Requires(body != null);
1214612147
this.body = body;
12148+
this.Attributes = attrs;
1214712149
}
1214812150

1214912151
public Expression Body {
@@ -12428,10 +12430,12 @@ public NestedMatchCase(IToken tok, ExtendedPattern pat) {
1242812430
public class NestedMatchCaseExpr : NestedMatchCase
1242912431
{
1243012432
public readonly Expression Body;
12433+
public Attributes Attributes;
1243112434

12432-
public NestedMatchCaseExpr(IToken tok, ExtendedPattern pat, Expression body): base(tok, pat) {
12435+
public NestedMatchCaseExpr(IToken tok, ExtendedPattern pat, Expression body, Attributes attrs): base(tok, pat) {
1243312436
Contract.Requires(body != null);
1243412437
this.Body = body;
12438+
this.Attributes = attrs;
1243512439
}
1243612440
}
1243712441

@@ -12496,13 +12500,15 @@ public class NestedMatchExpr : ConcreteSyntaxExpression
1249612500
public readonly Expression Source;
1249712501
public readonly List<NestedMatchCaseExpr> Cases;
1249812502
public readonly bool UsesOptionalBraces;
12503+
public Attributes Attributes;
1249912504

12500-
public NestedMatchExpr(IToken tok, Expression source, [Captured] List<NestedMatchCaseExpr> cases, bool usesOptionalBraces): base(tok) {
12505+
public NestedMatchExpr(IToken tok, Expression source, [Captured] List<NestedMatchCaseExpr> cases, bool usesOptionalBraces, Attributes attrs = null): base(tok) {
1250112506
Contract.Requires(source != null);
1250212507
Contract.Requires(cce.NonNullElements(cases));
1250312508
this.Source = source;
1250412509
this.Cases = cases;
1250512510
this.UsesOptionalBraces = usesOptionalBraces;
12511+
this.Attributes = attrs;
1250612512
}
1250712513
}
1250812514

Source/Dafny/Printer.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,7 +1892,9 @@ public void PrintExtendedExpr(Expression expr, int indent, bool isRightmost, boo
18921892
foreach (var mc in e.Cases) {
18931893
bool isLastCase = i == e.Cases.Count - 1;
18941894
Indent(ind);
1895-
wr.Write("case ");
1895+
wr.Write("case");
1896+
PrintAttributes(mc.Attributes);
1897+
wr.Write(" ");
18961898
PrintExtendedPattern(mc.Pat);
18971899
wr.WriteLine(" =>");
18981900
PrintExtendedExpr(mc.Body, ind + IndentAmount, isLastCase, isLastCase && (parensNeeded || endWithCloseParen));
@@ -1919,7 +1921,10 @@ public void PrintExtendedExpr(Expression expr, int indent, bool isRightmost, boo
19191921
foreach (var mc in e.Cases) {
19201922
bool isLastCase = i == e.Cases.Count - 1;
19211923
Indent(ind);
1922-
wr.Write("case {0}", mc.Ctor.Name);
1924+
wr.Write("case");
1925+
PrintAttributes(mc.Attributes);
1926+
wr.Write(" ");
1927+
wr.Write(mc.Ctor.Name);
19231928
PrintMatchCaseArgument(mc);
19241929
wr.WriteLine(" =>");
19251930
PrintExtendedExpr(mc.Body, ind + IndentAmount, isLastCase, isLastCase && (parensNeeded || endWithCloseParen));

Source/Dafny/Resolver.cs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Diagnostics.Contracts;
1414
using Microsoft.BaseTypes;
1515
using Microsoft.Boogie;
16+
using Microsoft.CodeAnalysis.CSharp.Syntax;
1617

1718
namespace Microsoft.Dafny
1819
{
@@ -11580,9 +11581,11 @@ public SyntaxContainer(IToken tok) {
1158011581
private class CExpr : SyntaxContainer
1158111582
{
1158211583
public readonly Expression Body;
11584+
public Attributes Attributes;
1158311585

11584-
public CExpr(IToken tok, Expression body) : base(tok) {
11586+
public CExpr(IToken tok, Expression body, Attributes attrs = null) : base(tok) {
1158511587
this.Body = body;
11588+
this.Attributes = attrs;
1158611589
}
1158711590
}
1158811591

@@ -11652,14 +11655,17 @@ public override string ToString() {
1165211655
private class RBranchExpr : RBranch {
1165311656

1165411657
public Expression Body;
11658+
public Attributes Attributes;
1165511659

11656-
public RBranchExpr(IToken tok, int branchid, List<ExtendedPattern> patterns, Expression body) : base(tok, branchid, patterns) {
11660+
public RBranchExpr(IToken tok, int branchid, List<ExtendedPattern> patterns, Expression body, Attributes attrs = null) : base(tok, branchid, patterns) {
1165711661
this.Body = body;
11662+
this.Attributes = attrs;
1165811663
}
1165911664

11660-
public RBranchExpr(int branchid, NestedMatchCaseExpr x) : base(x.Tok, branchid, new List<ExtendedPattern>()) {
11665+
public RBranchExpr(int branchid, NestedMatchCaseExpr x, Attributes attrs = null) : base(x.Tok, branchid, new List<ExtendedPattern>()) {
1166111666
this.Body = x.Body;
1166211667
this.Patterns.Add(x.Pat);
11668+
this.Attributes = attrs;
1166311669
}
1166411670

1166511671
public override string ToString() {
@@ -11675,7 +11681,7 @@ private static RBranchStmt CloneRBranchStmt(RBranchStmt branch) {
1167511681

1167611682
private static RBranchExpr CloneRBranchExpr(RBranchExpr branch) {
1167711683
Cloner cloner = new Cloner();
11678-
return new RBranchExpr(branch.Tok, branch.BranchID, branch.Patterns.ConvertAll(x => cloner.CloneExtendedPattern(x)), cloner.CloneExpr(branch.Body));
11684+
return new RBranchExpr(branch.Tok, branch.BranchID, branch.Patterns.ConvertAll(x => cloner.CloneExtendedPattern(x)), cloner.CloneExpr(branch.Body), cloner.CloneAttributes((branch.Attributes)));
1167911685
}
1168011686

1168111687
private static RBranch CloneRBranch(RBranch branch) {
@@ -11699,7 +11705,7 @@ private SyntaxContainer PackBody(IToken tok, RBranch branch) {
1169911705
if (branch is RBranchStmt br) {
1170011706
return new CStmt(tok, new BlockStmt(tok, tok, br.Body), br.Attributes);
1170111707
} else if (branch is RBranchExpr) {
11702-
return new CExpr(tok, ((RBranchExpr)branch).Body);
11708+
return new CExpr(tok, ((RBranchExpr)branch).Body, ((RBranchExpr)branch).Attributes);
1170311709
} else {
1170411710
Contract.Assert(false); throw new cce.UnreachableException(); // RBranch has only two implementations
1170511711
}
@@ -11817,7 +11823,8 @@ private MatchCase MakeMatchCaseFromContainer(IToken tok, KeyValuePair<string, Da
1181711823
newMatchCase = new MatchCaseStmt(tok, ctor.Value, freshPatBV, insideBranch, c.Attributes);
1181811824
} else {
1181911825
var insideBranch = ((CExpr)insideContainer).Body;
11820-
newMatchCase = new MatchCaseExpr(tok, ctor.Value, freshPatBV, insideBranch);
11826+
var attrs = ((CExpr)insideContainer).Attributes;
11827+
newMatchCase = new MatchCaseExpr(tok, ctor.Value, freshPatBV, insideBranch, attrs);
1182111828
}
1182211829
newMatchCase.Ctor = ctor.Value;
1182311830
return newMatchCase;
@@ -12036,7 +12043,7 @@ private SyntaxContainer CompileRBranchConstructor(MatchTempInfo mti, MatchingCon
1203612043
c.Attributes = new Attributes("split", args, c.Attributes);
1203712044
}
1203812045
var newMatchStmt = new MatchStmt(mti.Tok, mti.EndTok, currMatchee, newMatchCaseStmts, true, mti.Attributes, context);
12039-
return new CStmt(null, newMatchStmt); //Wokring HERE
12046+
return new CStmt(null, newMatchStmt);
1204012047
} else {
1204112048
var newMatchExpr = new MatchExpr(mti.Tok, currMatchee, newMatchCases.ConvertAll(x => (MatchCaseExpr)x), true, context);
1204212049
return new CExpr(null, newMatchExpr);
@@ -12164,7 +12171,7 @@ private void CompileNestedMatchExpr(NestedMatchExpr e, ResolveOpts opts) {
1216412171
List<RBranch> branches = new List<RBranch>();
1216512172
for (int id = 0; id < e.Cases.Count(); id++) {
1216612173
var branch = e.Cases.ElementAt(id);
12167-
branches.Add(new RBranchExpr(id, branch));
12174+
branches.Add(new RBranchExpr(id, branch, branch.Attributes));
1216812175
mti.BranchTok[id] = branch.Tok;
1216912176
}
1217012177

@@ -12410,6 +12417,7 @@ private void CheckLinearNestedMatchCase(Type type, NestedMatchCase mc, ResolveOp
1241012417
private void CheckLinearNestedMatchExpr(Type dtd, NestedMatchExpr me, ResolveOpts opts) {
1241112418
foreach(NestedMatchCaseExpr mc in me.Cases) {
1241212419
scope.PushMarker();
12420+
ResolveAttributes(mc.Attributes, null, opts);
1241312421
CheckLinearNestedMatchCase(dtd, mc, opts);
1241412422
scope.PopMarker();
1241512423
}

Source/Dafny/Verifier/Substituter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ public virtual Expression Substitute(Expression expr) {
256256
if (newBoundVars != mc.Arguments || body != mc.Body) {
257257
anythingChanged = true;
258258
}
259-
var newCaseExpr = new MatchCaseExpr(mc.tok, mc.Ctor, newBoundVars, body);
259+
var newCaseExpr = new MatchCaseExpr(mc.tok, mc.Ctor, newBoundVars, body, mc.Attributes);
260260
newCaseExpr.Ctor = mc.Ctor; // resolve here
261261
cases.Add(newCaseExpr);
262262
}

Test/dafny0/AttributeChecks.dfy

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ method Match(xs: List<int>) returns (r: int)
5353
}
5454
}
5555

56+
function method CaseExpr(r: List<int>): List<int>
57+
{
58+
match r {
59+
case Nil => Nil
60+
case {:ignore 3 + true} Cons(h, Nil) => Nil // error: 3 + true is ill-typed
61+
case {:ignore false} Cons(h, t) => CaseExpr(t)
62+
}
63+
}
64+
5665
method Calc(x: int, y: int)
5766
{
5867
calc {:split 1} {:split 1 + false} { // error: 1 + false is ill-typed

Test/dafny0/AttributeChecks.dfy.expect

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ method Match(xs: List<int>) returns (r: int)
6666
}
6767
}
6868

69+
function method CaseExpr(r: List<int>): List<int>
70+
{
71+
match r {
72+
case Nil =>
73+
Nil
74+
case {:ignore 3 + true} Cons(h, Nil) =>
75+
Nil
76+
case {:ignore false} Cons(h, t) =>
77+
CaseExpr(t)
78+
}
79+
}
80+
6981
method Calc(x: int, y: int)
7082
{
7183
calc {:split 1} {:split 1 + false} {
@@ -104,12 +116,12 @@ method For(lo: int, hi: int) returns (k: int)
104116
}
105117
return 2;
106118
}
107-
AttributeChecks.dfy(94,7): Error: unresolved identifier: k
108-
AttributeChecks.dfy(93,28): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
109-
AttributeChecks.dfy(93,28): Error: type of right argument to + (int) must agree with the result type (bool)
110-
AttributeChecks.dfy(97,25): Error: unresolved identifier: k
111-
AttributeChecks.dfy(96,28): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
112-
AttributeChecks.dfy(96,28): Error: type of right argument to + (int) must agree with the result type (bool)
119+
AttributeChecks.dfy(103,7): Error: unresolved identifier: k
120+
AttributeChecks.dfy(102,28): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
121+
AttributeChecks.dfy(102,28): Error: type of right argument to + (int) must agree with the result type (bool)
122+
AttributeChecks.dfy(106,25): Error: unresolved identifier: k
123+
AttributeChecks.dfy(105,28): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
124+
AttributeChecks.dfy(105,28): Error: type of right argument to + (int) must agree with the result type (bool)
113125
AttributeChecks.dfy(18,17): Error: type of left argument to + (int) must agree with the result type (bool)
114126
AttributeChecks.dfy(18,17): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
115127
AttributeChecks.dfy(28,35): Error: type of right argument to + (int) must agree with the result type (bool)
@@ -118,12 +130,14 @@ AttributeChecks.dfy(42,19): Error: type of left argument to + (int) must agree w
118130
AttributeChecks.dfy(42,19): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
119131
AttributeChecks.dfy(52,19): Error: type of left argument to + (int) must agree with the result type (bool)
120132
AttributeChecks.dfy(52,19): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
121-
AttributeChecks.dfy(58,28): Error: type of left argument to + (int) must agree with the result type (bool)
122-
AttributeChecks.dfy(58,28): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
123-
AttributeChecks.dfy(68,25): Error: type of left argument to + (int) must agree with the result type (bool)
124-
AttributeChecks.dfy(68,25): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
125-
AttributeChecks.dfy(75,23): Error: type of right argument to + (int) must agree with the result type (bool)
126-
AttributeChecks.dfy(75,23): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
127-
AttributeChecks.dfy(86,30): Error: type of right argument to + (int) must agree with the result type (bool)
128-
AttributeChecks.dfy(86,30): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
129-
22 resolution/type errors detected in AttributeChecks.dfy
133+
AttributeChecks.dfy(60,20): Error: type of left argument to + (int) must agree with the result type (bool)
134+
AttributeChecks.dfy(60,20): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
135+
AttributeChecks.dfy(67,28): Error: type of left argument to + (int) must agree with the result type (bool)
136+
AttributeChecks.dfy(67,28): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
137+
AttributeChecks.dfy(77,25): Error: type of left argument to + (int) must agree with the result type (bool)
138+
AttributeChecks.dfy(77,25): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
139+
AttributeChecks.dfy(84,23): Error: type of right argument to + (int) must agree with the result type (bool)
140+
AttributeChecks.dfy(84,23): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
141+
AttributeChecks.dfy(95,30): Error: type of right argument to + (int) must agree with the result type (bool)
142+
AttributeChecks.dfy(95,30): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool)
143+
24 resolution/type errors detected in AttributeChecks.dfy

0 commit comments

Comments
 (0)