Skip to content

Commit eb1caa5

Browse files
authored
[Civl] Change signature of Alloc (#1023)
The purpose of this PR is to make Alloc return the right loc piece. While making the change, I discovered a crash in the type checker. Added a fix for that.
1 parent 3134c06 commit eb1caa5

File tree

3 files changed

+64
-52
lines changed

3 files changed

+64
-52
lines changed

Source/Core/AST/Expression/AbsyExpr.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public enum Position
4242
Neither
4343
}
4444

45+
public static Type ErrorType = new TypeProxy(Token.NoToken, "type_checking_error");
46+
4547
public static Position NegatePosition(Position p)
4648
{
4749
return p == Position.Neither ? Position.Neither : (p == Position.Neg ? Position.Pos : Position.Neg);
@@ -1327,7 +1329,7 @@ public override void Typecheck(TypecheckingContext tc)
13271329
if (this.Decl != null)
13281330
{
13291331
// sanity check
1330-
if (Type != null && !Type.Equals(Decl.TypedIdent.Type))
1332+
if (Type != null && !Type.Equals(ErrorType) && !Type.Equals(Decl.TypedIdent.Type))
13311333
{
13321334
tc.Error(this, "internal error, shallow-type assignment was done incorrectly, {0}:{1} != {2}",
13331335
Name, Type, Decl.TypedIdent.Type);
@@ -4117,7 +4119,7 @@ public override void Typecheck(TypecheckingContext tc)
41174119

41184120
if (Type == null)
41194121
{
4120-
Type = new TypeProxy(this.tok, "type_checking_error");
4122+
Type = Expr.ErrorType;
41214123
}
41224124
}
41234125

@@ -4287,7 +4289,7 @@ public override void Typecheck(TypecheckingContext tc)
42874289

42884290
if (Type == null)
42894291
{
4290-
Type = new TypeProxy(this.tok, "type_checking_error");
4292+
Type = Expr.ErrorType;
42914293
}
42924294
}
42934295

Source/Core/AST/Expression/NAryExpr.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ public override void Typecheck(TypecheckingContext tc)
213213

214214
if (Type == null)
215215
{
216-
// set Type to some non-null value
217-
Type = new TypeProxy(this.tok, "type_checking_error");
216+
Type = Expr.ErrorType;
218217
}
219218
}
220219

Test/civl/large-samples/treiber-stack.bpl

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,44 @@ function {:inline} AllLocPieces(): Set LocPiece {
66
Set_Add(Set_Add(Set_Empty(), Left()), Right())
77
}
88

9+
type LocTreiberStack = KeyedLoc LocPiece;
910
type LocTreiberNode = KeyedLoc LocPiece;
1011
type StackElem T = Node LocTreiberNode T;
1112
type StackMap T = Map LocTreiberNode (StackElem T);
1213
datatype Treiber<T> { Treiber(top: Option LocTreiberNode, {:linear} nodes: StackMap T) }
1314

15+
function {:inline} LeftLocPiece(loc_piece: KeyedLoc LocPiece): KeyedLoc LocPiece {
16+
KeyedLoc(loc_piece->l, Left())
17+
}
18+
1419
type X; // module type parameter
1520

16-
var {:layer 4, 5} TreiberPool: Map Loc (Vec X);
17-
var {:layer 0, 4} {:linear} TreiberPoolLow: Map Loc (Treiber X);
21+
var {:layer 4, 5} TreiberPool: Map LocTreiberStack (Vec X);
22+
var {:layer 0, 4} {:linear} TreiberPoolLow: Map LocTreiberStack (Treiber X);
1823

1924
/// Yield invariants
2025

21-
function {:inline} Domain(ts: Map Loc (Treiber X), loc_t: Loc): Set LocTreiberNode {
26+
function {:inline} Domain(ts: Map LocTreiberStack (Treiber X), loc_t: LocTreiberStack): Set LocTreiberNode {
2227
ts->val[loc_t]->nodes->dom
2328
}
2429

2530
yield invariant {:layer 1} Yield();
2631

27-
yield invariant {:layer 2} TopInStack(loc_t: Loc);
32+
yield invariant {:layer 2} TopInStack(loc_t: LocTreiberStack);
2833
invariant Map_Contains(TreiberPoolLow, loc_t);
2934
invariant (var loc_n := Map_At(TreiberPoolLow, loc_t)->top; loc_n is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n->t));
3035
invariant (forall loc_n: LocTreiberNode :: Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n) ==>
3136
(var loc_n' := Map_At(Map_At(TreiberPoolLow, loc_t)->nodes, loc_n)->next; loc_n' is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n'->t)));
3237

33-
yield invariant {:layer 2} LocInStackOrNone(loc_t: Loc, loc_n: Option LocTreiberNode);
38+
yield invariant {:layer 2} LocInStackOrNone(loc_t: LocTreiberStack, loc_n: Option LocTreiberNode);
3439
invariant Map_Contains(TreiberPoolLow, loc_t);
3540
invariant loc_n is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n->t);
3641

37-
yield invariant {:layer 3} LocInStack(loc_t: Loc, loc_n: LocTreiberNode);
42+
yield invariant {:layer 3} LocInStack(loc_t: LocTreiberStack, loc_n: LocTreiberNode);
3843
invariant Map_Contains(TreiberPoolLow, loc_t);
3944
invariant Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n);
4045

41-
yield invariant {:layer 4} ReachInStack(loc_t: Loc);
46+
yield invariant {:layer 4} ReachInStack(loc_t: LocTreiberStack);
4247
invariant Map_Contains(TreiberPoolLow, loc_t);
4348
invariant (var t := TreiberPoolLow->val[loc_t]; Between(t->nodes->val, t->top, t->top, None()));
4449
invariant (var t := TreiberPoolLow->val[loc_t]; IsSubset(BetweenSet(t->nodes->val, t->top, None()), Domain(TreiberPoolLow, loc_t)->val));
@@ -49,7 +54,7 @@ invariant Map_At(TreiberPool, loc_t) == Abs(Map_At(TreiberPoolLow, loc_t));
4954
yield invariant {:layer 4} StackDom();
5055
invariant TreiberPool->dom == TreiberPoolLow->dom;
5156

52-
yield invariant {:layer 4} PushLocInStack(loc_t: Loc, node: StackElem X, new_loc_n: LocTreiberNode, {:linear} right_loc_piece: One LocTreiberNode);
57+
yield invariant {:layer 4} PushLocInStack(loc_t: LocTreiberStack, node: StackElem X, new_loc_n: LocTreiberNode, {:linear} right_loc_piece: One LocTreiberNode);
5358
invariant Map_Contains(TreiberPoolLow, loc_t);
5459
invariant Set_Contains(Domain(TreiberPoolLow, loc_t), new_loc_n);
5560
invariant new_loc_n == KeyedLoc(new_loc_n->l, Left());
@@ -58,38 +63,44 @@ invariant (var t := TreiberPoolLow->val[loc_t]; Map_At(t->nodes, new_loc_n) == n
5863

5964
/// Layered implementation
6065

61-
atomic action {:layer 5} AtomicAlloc() returns (loc_t: Loc)
66+
atomic action {:layer 5} AtomicAlloc() returns ({:linear} one_loc_t: One LocTreiberStack)
6267
modifies TreiberPool;
6368
{
64-
var {:linear} one_loc_t: One Loc;
69+
var loc: Loc;
70+
var {:linear} loc_pieces: Set LocTreiberNode;
71+
var {:linear} left_loc_piece: One LocTreiberNode;
6572

66-
call one_loc_t := Loc_New();
67-
loc_t := one_loc_t->val;
68-
assume !Map_Contains(TreiberPool, loc_t);
69-
TreiberPool := Map_Update(TreiberPool, loc_t, Vec_Empty());
73+
call loc, loc_pieces := KeyedLocSet_New(AllLocPieces());
74+
call one_loc_t := One_Get(loc_pieces, KeyedLoc(loc, Right()));
75+
call left_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Left()));
76+
assume !Map_Contains(TreiberPool, left_loc_piece->val);
77+
TreiberPool := Map_Update(TreiberPool, left_loc_piece->val, Vec_Empty());
7078
}
71-
yield procedure {:layer 4} Alloc() returns (loc_t: Loc)
79+
yield procedure {:layer 4} Alloc() returns ({:linear} one_loc_t: One LocTreiberStack)
7280
refines AtomicAlloc;
73-
ensures call TopInStack(loc_t);
74-
ensures call ReachInStack(loc_t);
81+
ensures call TopInStack(LeftLocPiece(one_loc_t->val));
82+
ensures call ReachInStack(LeftLocPiece(one_loc_t->val));
7583
preserves call StackDom();
7684
{
85+
var loc: Loc;
86+
var {:linear} loc_pieces: Set LocTreiberNode;
87+
var {:linear} left_loc_piece: One LocTreiberNode;
7788
var top: Option LocTreiberNode;
7889
var {:linear} stack: StackMap X;
7990
var {:linear} treiber: Treiber X;
80-
var {:linear} one_loc_t: One Loc;
8191

8292
top := None();
8393
call stack := Map_MakeEmpty();
8494
treiber := Treiber(top, stack);
85-
call one_loc_t := Loc_New();
86-
loc_t := one_loc_t->val;
87-
call AllocTreiber#0(one_loc_t, treiber);
88-
call {:layer 4} TreiberPool := Copy(Map_Update(TreiberPool, loc_t, Vec_Empty()));
95+
call loc, loc_pieces := KeyedLocSet_New(AllLocPieces());
96+
call one_loc_t := One_Get(loc_pieces, KeyedLoc(loc, Right()));
97+
call left_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Left()));
98+
call AllocTreiber#0(left_loc_piece, treiber);
99+
call {:layer 4} TreiberPool := Copy(Map_Update(TreiberPool, left_loc_piece->val, Vec_Empty()));
89100
call {:layer 4} AbsLemma(treiber);
90101
}
91102

92-
atomic action {:layer 5} AtomicPush(loc_t: Loc, x: X) returns (success: bool)
103+
atomic action {:layer 5} AtomicPush(loc_t: LocTreiberStack, x: X) returns (success: bool)
93104
modifies TreiberPool;
94105
{
95106
if (*) {
@@ -99,7 +110,7 @@ modifies TreiberPool;
99110
success := false;
100111
}
101112
}
102-
yield procedure {:layer 4} Push(loc_t: Loc, x: X) returns (success: bool)
113+
yield procedure {:layer 4} Push(loc_t: LocTreiberStack, x: X) returns (success: bool)
103114
refines AtomicPush;
104115
preserves call TopInStack(loc_t);
105116
preserves call ReachInStack(loc_t);
@@ -122,7 +133,7 @@ preserves call StackDom();
122133
}
123134
}
124135

125-
atomic action {:layer 5} AtomicPop(loc_t: Loc) returns (success: bool, x_opt: Option X)
136+
atomic action {:layer 5} AtomicPop(loc_t: LocTreiberStack) returns (success: bool, x_opt: Option X)
126137
modifies TreiberPool;
127138
{
128139
var stack: Vec X;
@@ -141,7 +152,7 @@ modifies TreiberPool;
141152
x_opt := None();
142153
}
143154
}
144-
yield procedure {:layer 4} Pop(loc_t: Loc) returns (success: bool, x_opt: Option X)
155+
yield procedure {:layer 4} Pop(loc_t: LocTreiberStack) returns (success: bool, x_opt: Option X)
145156
refines AtomicPop;
146157
preserves call TopInStack(loc_t);
147158
preserves call ReachInStack(loc_t);
@@ -155,12 +166,12 @@ preserves call StackDom();
155166
}
156167
}
157168

158-
atomic action {:layer 4} AtomicAllocNode#3(loc_t: Loc, x: X)
169+
atomic action {:layer 4} AtomicAllocNode#3(loc_t: LocTreiberStack, x: X)
159170
returns (loc_n: Option LocTreiberNode, new_loc_n: LocTreiberNode, {:linear} right_loc_piece: One LocTreiberNode)
160171
modifies TreiberPoolLow;
161172
asserts Map_Contains(TreiberPoolLow, loc_t);
162173
{
163-
var {:linear} one_loc_t: One Loc;
174+
var {:linear} one_loc_t: One LocTreiberStack;
164175
var {:linear} treiber: Treiber X;
165176
var top: Option LocTreiberNode;
166177
var {:linear} stack: StackMap X;
@@ -179,7 +190,7 @@ asserts Map_Contains(TreiberPoolLow, loc_t);
179190
treiber := Treiber(top, stack);
180191
call Map_Put(TreiberPoolLow, one_loc_t, treiber);
181192
}
182-
yield procedure {:layer 3} AllocNode#3(loc_t: Loc, x: X)
193+
yield procedure {:layer 3} AllocNode#3(loc_t: LocTreiberStack, x: X)
183194
returns (loc_n: Option LocTreiberNode, new_loc_n: LocTreiberNode, {:linear} right_loc_piece: One LocTreiberNode)
184195
preserves call TopInStack(loc_t);
185196
ensures call LocInStackOrNone(loc_t, Some(new_loc_n));
@@ -197,10 +208,10 @@ refines AtomicAllocNode#3;
197208
call AllocNode#0(loc_t, left_loc_piece, Node(loc_n, x));
198209
}
199210

200-
atomic action {:layer 4} AtomicPopIntermediate(loc_t: Loc) returns (success: bool, x_opt: Option X)
211+
atomic action {:layer 4} AtomicPopIntermediate(loc_t: LocTreiberStack) returns (success: bool, x_opt: Option X)
201212
modifies TreiberPoolLow;
202213
{
203-
var {:linear} one_loc_t: One Loc;
214+
var {:linear} one_loc_t: One LocTreiberStack;
204215
var loc_n: Option LocTreiberNode;
205216
var {:linear} treiber: Treiber X;
206217
var top: Option LocTreiberNode;
@@ -227,7 +238,7 @@ modifies TreiberPoolLow;
227238
success := false;
228239
}
229240
}
230-
yield procedure {:layer 3} PopIntermediate(loc_t: Loc) returns (success: bool, x_opt: Option X)
241+
yield procedure {:layer 3} PopIntermediate(loc_t: LocTreiberStack) returns (success: bool, x_opt: Option X)
231242
refines AtomicPopIntermediate;
232243
preserves call TopInStack(loc_t);
233244
{
@@ -253,33 +264,33 @@ preserves call TopInStack(loc_t);
253264
}
254265
}
255266

256-
right action {:layer 3} AtomicReadTopOfStack#Push(loc_t: Loc) returns (loc_n: Option LocTreiberNode)
267+
right action {:layer 3} AtomicReadTopOfStack#Push(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
257268
{
258269
assert Map_Contains(TreiberPoolLow, loc_t);
259270
assume loc_n is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n->t);
260271
}
261-
yield procedure {:layer 2} ReadTopOfStack#Push(loc_t: Loc) returns (loc_n: Option LocTreiberNode)
272+
yield procedure {:layer 2} ReadTopOfStack#Push(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
262273
preserves call TopInStack(loc_t);
263274
ensures call LocInStackOrNone(loc_t, loc_n);
264275
refines AtomicReadTopOfStack#Push;
265276
{
266277
call loc_n := ReadTopOfStack#0(loc_t);
267278
}
268279

269-
atomic action {:layer 3} AtomicReadTopOfStack#Pop(loc_t: Loc) returns (loc_n: Option LocTreiberNode)
280+
atomic action {:layer 3} AtomicReadTopOfStack#Pop(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
270281
{
271282
assert Map_Contains(TreiberPoolLow, loc_t);
272283
assume if loc_n is None then Map_At(TreiberPoolLow, loc_t)->top is None else Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n->t);
273284
}
274-
yield procedure {:layer 2} ReadTopOfStack#Pop(loc_t: Loc) returns (loc_n: Option LocTreiberNode)
285+
yield procedure {:layer 2} ReadTopOfStack#Pop(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
275286
preserves call TopInStack(loc_t);
276287
ensures call LocInStackOrNone(loc_t, loc_n);
277288
refines AtomicReadTopOfStack#Pop;
278289
{
279290
call loc_n := ReadTopOfStack#0(loc_t);
280291
}
281292

282-
right action {:layer 2,3} AtomicLoadNode#1(loc_t: Loc, loc_n: LocTreiberNode) returns (node: StackElem X)
293+
right action {:layer 2,3} AtomicLoadNode#1(loc_t: LocTreiberStack, loc_n: LocTreiberNode) returns (node: StackElem X)
283294
{
284295
assert Map_Contains(TreiberPoolLow, loc_t);
285296
assert Map_Contains(Map_At(TreiberPoolLow, loc_t)->nodes, loc_n);
@@ -288,11 +299,11 @@ right action {:layer 2,3} AtomicLoadNode#1(loc_t: Loc, loc_n: LocTreiberNode) re
288299

289300
/// Primitives
290301

291-
atomic action {:layer 1} AtomicLoadNode#0(loc_t: Loc, loc_n: LocTreiberNode) returns (node: StackElem X)
302+
atomic action {:layer 1} AtomicLoadNode#0(loc_t: LocTreiberStack, loc_n: LocTreiberNode) returns (node: StackElem X)
292303
modifies TreiberPoolLow;
293304
refines AtomicLoadNode#1;
294305
{
295-
var {:linear} one_loc_t: One Loc;
306+
var {:linear} one_loc_t: One LocTreiberStack;
296307
var {:linear} treiber: Treiber X;
297308
var top: Option LocTreiberNode;
298309
var {:linear} stack: StackMap X;
@@ -305,13 +316,13 @@ refines AtomicLoadNode#1;
305316
treiber := Treiber(top, stack);
306317
call Map_Put(TreiberPoolLow, one_loc_t, treiber);
307318
}
308-
yield procedure {:layer 0} LoadNode#0(loc_t: Loc, loc_n: LocTreiberNode) returns (node: StackElem X);
319+
yield procedure {:layer 0} LoadNode#0(loc_t: LocTreiberStack, loc_n: LocTreiberNode) returns (node: StackElem X);
309320
refines AtomicLoadNode#0;
310321

311-
yield procedure {:layer 0} ReadTopOfStack#0(loc_t: Loc) returns (loc_n: Option LocTreiberNode);
322+
yield procedure {:layer 0} ReadTopOfStack#0(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode);
312323
refines atomic action {:layer 1,2} _
313324
{
314-
var {:linear} one_loc_t: One Loc;
325+
var {:linear} one_loc_t: One LocTreiberStack;
315326
var {:linear} treiber: Treiber X;
316327

317328
call one_loc_t, treiber := Map_Get(TreiberPoolLow, loc_t);
@@ -320,10 +331,10 @@ refines atomic action {:layer 1,2} _
320331
}
321332

322333
yield procedure {:layer 0} WriteTopOfStack#0(
323-
loc_t: Loc, old_loc_n: Option LocTreiberNode, new_loc_n: Option LocTreiberNode) returns (success: bool);
334+
loc_t: LocTreiberStack, old_loc_n: Option LocTreiberNode, new_loc_n: Option LocTreiberNode) returns (success: bool);
324335
refines atomic action {:layer 1,4} _
325336
{
326-
var {:linear} one_loc_t: One Loc;
337+
var {:linear} one_loc_t: One LocTreiberStack;
327338
var {:linear} treiber: Treiber X;
328339

329340
call one_loc_t, treiber := Map_Get(TreiberPoolLow, loc_t);
@@ -336,18 +347,18 @@ refines atomic action {:layer 1,4} _
336347
call Map_Put(TreiberPoolLow, one_loc_t, treiber);
337348
}
338349

339-
yield procedure {:layer 0} AllocNode#0(loc_t: Loc, {:linear_in} loc_piece: One LocTreiberNode, node: StackElem X);
350+
yield procedure {:layer 0} AllocNode#0(loc_t: LocTreiberStack, {:linear_in} loc_piece: One LocTreiberNode, node: StackElem X);
340351
refines atomic action {:layer 1,3} _
341352
{
342-
var {:linear} one_loc_t: One Loc;
353+
var {:linear} one_loc_t: One LocTreiberStack;
343354
var {:linear} treiber: Treiber X;
344355

345356
call one_loc_t, treiber := Map_Get(TreiberPoolLow, loc_t);
346357
call Map_Put(treiber->nodes, loc_piece, node);
347358
call Map_Put(TreiberPoolLow, one_loc_t, treiber);
348359
}
349360

350-
yield procedure {:layer 0} AllocTreiber#0({:linear_in} one_loc_t: One Loc, {:linear_in} treiber: Treiber X);
361+
yield procedure {:layer 0} AllocTreiber#0({:linear_in} one_loc_t: One LocTreiberStack, {:linear_in} treiber: Treiber X);
351362
refines atomic action {:layer 1,4} _
352363
{
353364
call Map_Put(TreiberPoolLow, one_loc_t, treiber);

0 commit comments

Comments
 (0)