Skip to content

Commit 3ae6fb5

Browse files
authored
contracts: fixes and tests assignments (#833)
* fixes and tests assignments * contracts: proper IR traversals
1 parent 5ca94b9 commit 3ae6fb5

File tree

5 files changed

+105
-20
lines changed

5 files changed

+105
-20
lines changed

src/nimony/contracts.nim

+78-12
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ type
3232
indegree, touched: int
3333
indegreeFacts: Facts
3434
Context = object
35-
cf, dest: TokenBuf
35+
cf, dest, toplevelStmts: TokenBuf
36+
routines: seq[Cursor]
3637
typeCache: TypeCache
3738
facts: Facts
3839
writesTo: seq[SymId]
@@ -123,9 +124,11 @@ proc compileCmp(c: var Context; paramMap: Table[SymId, int]; req, call: Cursor):
123124
b = mapSymbol(c, paramMap, call, r.symId)
124125
inc r
125126
elif r.kind == IntLit:
127+
b = VarId(0)
126128
cnst = createXint(pool.integers[r.intId])
127129
inc r
128130
elif r.kind == UIntLit:
131+
b = VarId(0)
129132
cnst = createXint(pool.uintegers[r.uintId])
130133
inc r
131134
elif (let op = r.exprKind; op in {AddX, SubX}):
@@ -300,10 +303,12 @@ proc rightHandSide(c: var Context; pc: var Cursor; fact: var LeXplusC): bool =
300303
result = true
301304
inc pc
302305
elif pc.kind == IntLit:
306+
fact.b = VarId(0)
303307
fact.c = fact.c + createXint(pool.integers[pc.intId])
304308
result = true
305309
inc pc
306310
elif pc.kind == UIntLit:
311+
fact.b = VarId(0)
307312
fact.c = fact.c + createXint(pool.uintegers[pc.uintId])
308313
result = true
309314
inc pc
@@ -537,7 +542,7 @@ proc decAndTest(x: var int): bool {.inline.} =
537542
result = x == 0
538543

539544
proc takeFacts(c: var Context; bb: var BasicBlock; conditionalFacts: int; negate: bool) =
540-
let start = bb.indegreeFacts.len
545+
#let start = bb.indegreeFacts.len
541546
if bb.touched == 0:
542547
for i in 1 ..< c.facts.len - conditionalFacts:
543548
bb.indegreeFacts.add c.facts[i]
@@ -557,10 +562,20 @@ proc pushFacts(c: var Context; bb: var BasicBlock) =
557562
for i in 0 ..< bb.indegreeFacts.len:
558563
c.facts.add bb.indegreeFacts[i]
559564

560-
proc checkContracts(c: var Context) =
561-
var bbs = computeBasicBlocks(c.cf)
565+
proc checkContracts(c: var Context; n: Cursor) =
566+
c.cf = toControlflow(n)
567+
c.facts = createFacts()
568+
freeze c.cf
569+
#echo "CF IS ", codeListing(c.cf)
570+
562571
c.startInstr = readonlyCursorAt(c.cf, 0)
563-
var current = BasicBlockIdx(0)
572+
var body = c.startInstr
573+
if body.stmtKind in {ProcS, FuncS, IteratorS, ConverterS, MethodS, MacroS}:
574+
inc body
575+
for i in 0 ..< BodyPos: skip body
576+
577+
var current = BasicBlockIdx(cursorToPosition(c.cf, body))
578+
var bbs = computeBasicBlocks(c.cf, current.int)
564579
var nextIter = true
565580
var candidates = newSeq[BasicBlockIdx]()
566581
while nextIter or candidates.len > 0:
@@ -588,17 +603,68 @@ proc checkContracts(c: var Context) =
588603
else:
589604
candidates.add cont.elsePart
590605

606+
proc traverseProc(c: var Context; n: var Cursor) =
607+
let orig = n
608+
let r = takeRoutine(n, SkipExclBody)
609+
skip n # effects
610+
if not isGeneric(r):
611+
c.routines.add orig
612+
var nested = 0
613+
while true:
614+
# don't forget about inner procs:
615+
let sk = n.stmtKind
616+
if sk in {ProcS, FuncS, IteratorS, ConverterS, MethodS}:
617+
traverseProc(c, n)
618+
elif sk in {MacroS, TemplateS, TypeS, CommentS, PragmasS}:
619+
skip n
620+
elif n.kind == ParLe:
621+
inc nested
622+
inc n
623+
elif n.kind == ParRi:
624+
dec nested
625+
inc n
626+
if nested == 0: break
627+
else:
628+
inc n
629+
skipParRi n
630+
else:
631+
skip n # body
632+
skipParRi n
633+
634+
proc traverseToplevel(c: var Context; n: var Cursor) =
635+
case n.stmtKind
636+
of StmtsS:
637+
c.toplevelStmts.add n
638+
inc n
639+
while n.kind != ParRi:
640+
traverseToplevel(c, n)
641+
c.toplevelStmts.add n
642+
skipParRi n
643+
of ProcS, FuncS, IteratorS, ConverterS, MethodS:
644+
traverseProc(c, n)
645+
of MacroS, TemplateS, TypeS, CommentS, PragmasS,
646+
ImportasS, ExportexceptS, BindS, MixinS, UsingS,
647+
ExportS,
648+
IncludeS, ImportS, FromimportS, ImportExceptS:
649+
skip n
650+
of IfS, WhenS, WhileS, ForS, CaseS, TryS, YldS, RaiseS,
651+
UnpackDeclS, StaticstmtS, AsmS, DeferS,
652+
CallS, CmdS, GvarS, TvarS, VarS, ConstS, ResultS,
653+
GletS, TletS, LetS, CursorS, BlockS, EmitS, AsgnS, ScopeS,
654+
BreakS, ContinueS, RetS, InclS, ExclS, DiscardS, AssumeS, AssertS, NoStmt:
655+
c.toplevelStmts.takeTree n
656+
591657
proc analyzeContracts*(input: var TokenBuf): TokenBuf =
592658
let oldInfos = prepare(input)
593659
var c = Context(typeCache: createTypeCache(),
594-
dest: createTokenBuf(500),
595-
cf: toControlflow(beginRead input),
596-
facts: createFacts())
597-
freeze c.cf
598-
#echo "CF IS ", codeListing(c.cf)
660+
dest: createTokenBuf(500))
599661
c.typeCache.openScope()
600-
601-
checkContracts(c)
662+
var n = beginRead(input)
663+
traverseToplevel c, n
664+
for r in c.routines:
665+
checkContracts(c, r)
666+
var nt = beginRead c.toplevelStmts
667+
checkContracts(c, nt)
602668

603669
endRead input
604670
restore(input, oldInfos)

src/nimony/controlflow.nim

+11-7
Original file line numberDiff line numberDiff line change
@@ -810,15 +810,19 @@ proc trExpr(c: var ControlFlow; n: var Cursor) =
810810

811811
proc toControlflow*(n: Cursor): TokenBuf =
812812
var c = ControlFlow(typeCache: createTypeCache())
813-
assert n.stmtKind == StmtsS
814813
c.typeCache.openScope()
814+
let sk = n.stmtKind
815815
var n = n
816-
c.dest.add n
817-
inc n
818-
while n.kind != ParRi:
819-
trStmt c, n
820-
c.dest.addParPair RetS, NoLineInfo
821-
c.dest.addParRi()
816+
if sk in {ProcS, FuncS, IteratorS, ConverterS, MethodS, MacroS}:
817+
trProc c, n
818+
else:
819+
assert sk == StmtsS
820+
c.dest.add n
821+
inc n
822+
while n.kind != ParRi:
823+
trStmt c, n
824+
c.dest.addParPair RetS, NoLineInfo
825+
c.dest.addParRi()
822826
c.typeCache.closeScope()
823827
result = ensureMove c.dest
824828
#echo "result: ", codeListing(result)

src/nimony/inferle.nim

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ proc implies*(facts: Facts; v: LeXplusC): bool =
185185

186186
proc merge*(x: Facts; xstart: int; y: Facts; negate: bool): Facts =
187187
# computes thing we know on a joint point.
188-
# we know that `a <= b + c` and `a <= b + d` then we know
188+
# we know that `a <= b + c` or `a <= b + d` then we know
189189
# that `a <= b + max(c, d)`
190190
result = Facts()
191191
for i in 0 ..< xstart:

tests/contracts/tasgn.msgs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OK 0 <= v3 + -0

tests/contracts/tasgn.nif

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
(stmts
2+
(proc :my.proc . . . (params (param :cond.0 . . (bool) .)) . . . (stmts
3+
(var :x.0 . . (i +32) .)
4+
(if
5+
(elif (cond.0) (stmts
6+
(asgn x.0 +12)
7+
))
8+
(else (stmts
9+
(asgn x.0 +14)
10+
))
11+
)
12+
(assert (out) (le . +0 x.0))
13+
))
14+
)

0 commit comments

Comments
 (0)