Skip to content

Commit 3c91407

Browse files
authored
fix: Avoid name capture in :- desugaring (#1095)
1 parent 9eeae85 commit 3c91407

File tree

3 files changed

+158
-3
lines changed

3 files changed

+158
-3
lines changed

Source/Dafny/Resolver.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12353,8 +12353,8 @@ private void ResolveAssignOrReturnStmt(AssignOrReturnStmt s, ICodeContext codeCo
1235312353

1235412354
// We need to figure out whether we are using a status type that has Extract or not,
1235512355
// as that determines how the AssignOrReturnStmt is desugared. Thus if the Rhs is a
12356-
// method call we need to know which one (to inpsectx its first output); if RHs is a
12357-
// list of expressions, we need to know the type of the first one. FOr all of this we have
12356+
// method call we need to know which one (to inspect its first output); if RHs is a
12357+
// list of expressions, we need to know the type of the first one. For all of this we have
1235812358
// to do some partial type resolution.
1235912359

1236012360
bool expectExtract = s.Lhss.Count != 0; // default value if we cannot determine and inspect the type
@@ -12514,13 +12514,20 @@ private void ResolveAssignOrReturnStmt(AssignOrReturnStmt s, ICodeContext codeCo
1251412514
}
1251512515
s.ResolvedStatements.Add(ss);
1251612516
} else {
12517+
var enclosingOutParameter = ((Method)codeContext).Outs[0];
12518+
var ident = new IdentifierExpr(s.Tok, enclosingOutParameter.Name);
12519+
// resolve it here to avoid capture into more closely declared local variables
12520+
Contract.Assert(enclosingOutParameter.Type != null); // this confirms our belief that the out-parameter has already been resolved
12521+
ident.Var = enclosingOutParameter;
12522+
ident.Type = ident.Var.Type;
12523+
1251712524
s.ResolvedStatements.Add(
1251812525
// "if temp.IsFailure()"
1251912526
new IfStmt(s.Tok, s.Tok, false, VarDotMethod(s.Tok, temp, "IsFailure"),
1252012527
// THEN: { out := temp.PropagateFailure(); return; }
1252112528
new BlockStmt(s.Tok, s.Tok, new List<Statement>() {
1252212529
new UpdateStmt(s.Tok, s.Tok,
12523-
new List<Expression>() {new IdentifierExpr(s.Tok, (codeContext as Method).Outs[0].CompileName)},
12530+
new List<Expression>() { ident },
1252412531
new List<AssignmentRhs>() {new ExprRhs(VarDotMethod(s.Tok, temp, "PropagateFailure"))}
1252512532
),
1252612533
new ReturnStmt(s.Tok, s.Tok, null),

Test/git-issues/git-issue-1094.dfy

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// RUN: %dafny /compile:0 "%s" > "%t"
2+
// RUN: %diff "%s.expect" "%t"
3+
4+
// ----- Type error -----
5+
6+
method FP() returns (r: FStatus)
7+
{
8+
{
9+
var r: int; // this variable shadows the out-parameter r
10+
:- FTry(); // regression: this once gave an error saying RHS (of type FStatus) not assignable to LHS (of type int)
11+
}
12+
}
13+
14+
method MP() returns (r: MStatus)
15+
{
16+
{
17+
var r: int; // this variable shadows the out-parameter r
18+
:- MTry(); // regression: this once gave an error saying RHS (of type MStatus) not assignable to LHS (of type int)
19+
}
20+
}
21+
22+
method FQ() returns (r: FResult<int>)
23+
ensures r == FResult.Failure(5)
24+
{
25+
{
26+
var r: int; // this variable shadows the out-parameter r
27+
var x :- FCompute(); // regression: this once gave an error saying RHS (of type FResult<?>) not assignable to LHS (of type int)
28+
}
29+
}
30+
31+
method MQ() returns (r: MResult<int>)
32+
ensures r == MResult.Failure(5)
33+
{
34+
{
35+
var r: int; // this variable shadows the out-parameter r
36+
var x :- MCompute(); // regression: this once gave an error saying RHS (of type MResult<?>) not assignable to LHS (of type int)
37+
}
38+
}
39+
40+
// ----- Verification error -----
41+
42+
method FS() returns (r: FStatus)
43+
ensures r == FStatus.Error(5)
44+
{
45+
{
46+
var r: FStatus; // this variable shadows the out-parameter r
47+
:- FTry(); // regression: this once resulted in a reported postcondition violation
48+
}
49+
}
50+
51+
method MS() returns (r: MStatus)
52+
ensures r == MStatus.Error(5)
53+
{
54+
{
55+
var r: MStatus; // this variable shadows the out-parameter r
56+
:- MTry(); // regression: this once resulted in a reported postcondition violation
57+
}
58+
}
59+
60+
method FR() returns (r: FResult<int>)
61+
ensures r == FResult.Failure(5)
62+
{
63+
{
64+
var r: FResult<int>; // this variable shadows the out-parameter r
65+
var x :- FCompute(); // regression: this once resulted in a reported postcondition violation
66+
}
67+
}
68+
69+
method MR() returns (r: MResult<int>)
70+
ensures r == MResult.Failure(5)
71+
{
72+
{
73+
var r: MResult<int>; // this variable shadows the out-parameter r
74+
var x :- MCompute(); // regression: this once resulted in a reported postcondition violation
75+
}
76+
}
77+
78+
// ----- Aux definitions -----
79+
80+
method FTry() returns (status: FStatus)
81+
ensures status == FStatus.Error(5)
82+
83+
method MTry() returns (status: MStatus)
84+
ensures status == MStatus.Error(5)
85+
86+
datatype FStatus = Okay | Error(code: int) {
87+
predicate method IsFailure() {
88+
Error?
89+
}
90+
function method PropagateFailure(): FStatus
91+
requires Error?
92+
{
93+
this
94+
}
95+
}
96+
97+
datatype MStatus = Okay | Error(code: int) {
98+
predicate method IsFailure() {
99+
Error?
100+
}
101+
method PropagateFailure() returns (m: MStatus)
102+
requires Error?
103+
ensures m == this
104+
{
105+
return this;
106+
}
107+
}
108+
109+
method FCompute() returns (result: FResult<int>)
110+
ensures result == FResult.Failure(5)
111+
112+
method MCompute() returns (result: MResult<int>)
113+
ensures result == MResult.Failure(5)
114+
115+
datatype FResult<X> = Success(x: X) | Failure(code: int) {
116+
predicate method IsFailure() {
117+
Failure?
118+
}
119+
function method PropagateFailure<U>(): FResult<U>
120+
requires Failure?
121+
{
122+
FResult.Failure(code)
123+
}
124+
function method Extract(): X
125+
requires Success?
126+
{
127+
x
128+
}
129+
}
130+
131+
datatype MResult<X> = Success(x: X) | Failure(code: int) {
132+
predicate method IsFailure() {
133+
Failure?
134+
}
135+
method PropagateFailure<U>() returns (result: MResult<U>)
136+
requires Failure?
137+
ensures result.Failure? && result.code == code
138+
{
139+
return MResult.Failure(code);
140+
}
141+
method Extract() returns (result: X)
142+
requires Success?
143+
{
144+
return x;
145+
}
146+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
Dafny program verifier finished with 14 verified, 0 errors

0 commit comments

Comments
 (0)