Skip to content

Commit 9237bb5

Browse files
authored
not nil progress (#1089)
1 parent b68c1e3 commit 9237bb5

File tree

6 files changed

+114
-10
lines changed

6 files changed

+114
-10
lines changed

lib/std/system.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,5 @@ func chr*(u: range[0..255]): char {.inline.} =
192192
char(u.int)
193193

194194
include "../../vendor/errorcodes/src" / errorcodes
195+
196+
var localErr* {.threadvar.}: ErrorCode

src/nimony/contracts.nim

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,75 @@ proc checkReq(c: var Context; paramMap: Table[SymId, int]; req, call: Cursor): P
216216

217217
proc analyseCall(c: var Context; n: var Cursor)
218218

219+
proc markedNotNil(t: Cursor): bool =
220+
result = false
221+
case t.typeKind
222+
of PtrT, RefT:
223+
var e = t.firstSon
224+
skip e # base type
225+
if e.kind != ParRi and e.substructureKind == NotnilU:
226+
result = true
227+
of CstringT, PointerT:
228+
let e = t.firstSon
229+
# no base type
230+
if e.kind != ParRi and e.substructureKind == NotnilU:
231+
result = true
232+
else:
233+
discard
234+
235+
proc wantNotNil(c: var Context; n: Cursor) =
236+
case n.exprKind
237+
of NilX:
238+
buildErr(c, n.info, "expected non-nil value")
239+
of AddrX:
240+
discard "fine, addresses are not nil"
241+
else:
242+
let t = getType(c.typeCache, n)
243+
if markedNotNil(t):
244+
discard "fine, per type we know it is not nil"
245+
#elif n.kind
246+
# XXX to implement
247+
248+
proc checkNilMatch(c: var Context; n: Cursor; expected: Cursor) =
249+
if markedNotNil(expected):
250+
wantNotNil c, n
251+
252+
proc analyseOconstr(c: var Context; n: var Cursor) =
253+
inc n
254+
skip n # type
255+
while n.kind != ParRi:
256+
assert n.substructureKind == KvU
257+
inc n
258+
let expected = getType(c.typeCache, n)
259+
skip n # field name
260+
checkNilMatch c, n, expected
261+
skip n # value
262+
if n.kind != ParRi:
263+
# optional inheritance
264+
skip n
265+
skipParRi n
266+
skipParRi n
267+
268+
proc analyseArrayConstr(c: var Context; n: var Cursor) =
269+
inc n
270+
let expected = n.firstSon # element type of the array
271+
skip n # type
272+
while n.kind != ParRi:
273+
checkNilMatch c, n, expected
274+
skip n
275+
skipParRi n
276+
277+
proc analyseTupConstr(c: var Context; n: var Cursor) =
278+
inc n
279+
var expected = n.firstSon # type of the first field
280+
skip n # type
281+
while n.kind != ParRi:
282+
assert expected.kind != ParRi
283+
checkNilMatch c, n, getTupleFieldType(expected)
284+
skip n
285+
skip expected # type of the next field
286+
skipParRi n
287+
219288
proc analyseExpr(c: var Context; pc: var Cursor) =
220289
#echo "analyseExpr ", toString(pc, false)
221290
var nested = 0
@@ -239,8 +308,27 @@ proc analyseExpr(c: var Context; pc: var Cursor) =
239308
dec nested
240309
inc pc
241310
of ParLe:
242-
if pc.exprKind in CallKinds:
311+
case pc.exprKind
312+
of CallKinds:
243313
analyseCall c, pc
314+
of DdotX:
315+
inc pc
316+
wantNotNil c, pc
317+
analyseExpr c, pc # object
318+
skip pc # field name
319+
if pc.kind != ParRi: skip pc # inheritence depth
320+
skipParRi pc
321+
of DerefX:
322+
inc pc
323+
wantNotNil c, pc
324+
analyseExpr c, pc
325+
skipParRi pc
326+
of OconstrX, NewobjX:
327+
analyseOconstr c, pc
328+
of AconstrX:
329+
analyseArrayConstr c, pc
330+
of TupconstrX:
331+
analyseTupConstr c, pc
244332
else:
245333
inc nested
246334
inc pc
@@ -265,6 +353,7 @@ proc analyseCallArgs(c: var Context; n: var Cursor) =
265353
elif pk == VarargsT:
266354
# do not advance formal parameter:
267355
fnType = previousFormalParam
356+
checkNilMatch c, n, param.typ
268357
analyseExpr c, n
269358
while fnType.kind != ParRi: skip fnType
270359
inc fnType # skip ParRi
@@ -493,6 +582,7 @@ proc addAsgnFact(c: var Context; fact: LeXplusC) =
493582

494583
proc analyseAsgn(c: var Context; pc: var Cursor) =
495584
inc pc # skip asgn instruction
585+
let expected = getType(c.typeCache, pc)
496586
if pc.kind == Symbol:
497587
let symId = pc.symId
498588
let x = getLocalInfo(c.typeCache, symId)
@@ -504,6 +594,7 @@ proc analyseAsgn(c: var Context; pc: var Cursor) =
504594
c.writesTo.add symId
505595
# after `x = 4` we know two facts: `x >= 4` and `x <= 4`
506596
inc pc
597+
checkNilMatch c, pc, expected
507598
if rightHandSide(c, pc, fact):
508599
if fact.a == fact.b:
509600
variableChangedByDiff(c.facts, fact.a, fact.c)
@@ -514,6 +605,7 @@ proc analyseAsgn(c: var Context; pc: var Cursor) =
514605
invalidateFactsAbout(c.facts, fact.a)
515606
else:
516607
analyseExpr c, pc
608+
checkNilMatch c, pc, expected
517609
analyseExpr c, pc
518610
skipParRi pc
519611

src/nimony/controlflow.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import std/[assertions, intsets]
1111
include nifprelude
1212

13-
import nimony_model, programs, typenav
13+
import nimony_model, programs, builtintypes, typenav
1414
from typeprops import isOrdinalType
1515

1616
const
@@ -730,13 +730,13 @@ proc trLocal(c: var ControlFlow; n: var Cursor) =
730730
c.dest.add aa
731731

732732
proc trRaise(c: var ControlFlow; n: var Cursor) =
733-
# we map `raise x` to `currexc = x; return`.
733+
# we map `raise x` to `localErr = x; return`.
734734
let info = n.info
735735
inc n
736736
var aa = Target(m: IsEmpty)
737737
trExpr c, n, aa
738738
c.dest.addParLe(AsgnS, info)
739-
c.dest.addSymUse pool.syms.getOrIncl("currexc.0.sys"), info
739+
c.dest.addSymUse pool.syms.getOrIncl("localErr.0." & SystemModuleSuffix), info
740740
c.dest.add aa
741741
c.dest.addParRi()
742742
skipParRi n

src/nimony/sem.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,7 +3126,7 @@ proc handleNotnilType(c: var SemContext; nn: var Cursor; context: TypeDeclContex
31263126
if n.exprKind == NilX:
31273127
skip n
31283128
let nd = cursorAt(c.dest, before)
3129-
if nd.typeKind in {RefT, PtrT}:
3129+
if nd.typeKind in {RefT, PtrT, PointerT, CstringT}:
31303130
c.dest.endRead()
31313131
# remove ParRi of the pointer
31323132
c.dest.shrink c.dest.len-1
@@ -3179,7 +3179,7 @@ proc handleNilableType(c: var SemContext; nn: var Cursor; context: TypeDeclConte
31793179
let before = c.dest.len
31803180
semLocalTypeImpl c, n, context
31813181
let nd = cursorAt(c.dest, before)
3182-
if nd.typeKind in {RefT, PtrT}:
3182+
if nd.typeKind in {RefT, PtrT, PointerT, CstringT}:
31833183
c.dest.endRead()
31843184
# remove ParRi of the pointer
31853185
c.dest.shrink c.dest.len-1

src/nimony/sigmatch.nim

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -997,8 +997,13 @@ proc singleArgImpl(m: var Match; f: var Cursor; arg: Item) =
997997
inc m.convCosts
998998
inc f
999999
expectParRi m, f
1000+
elif a.typeKind == CstringT:
1001+
inc f
1002+
inc a
1003+
expectPtrParRi m, f
1004+
expectPtrParRi m, a
10001005
else:
1001-
linearMatch m, f, a
1006+
m.error InvalidMatch, f, a
10021007
of PointerT:
10031008
var a = skipModifier(arg.typ)
10041009
case a.typeKind
@@ -1012,9 +1017,14 @@ proc singleArgImpl(m: var Match; f: var Cursor; arg: Item) =
10121017
inc m.opened
10131018
inc m.convCosts
10141019
inc f
1015-
expectParRi m, f
1020+
expectPtrParRi m, f
1021+
of PointerT:
1022+
inc f
1023+
inc a
1024+
expectPtrParRi m, f
1025+
expectPtrParRi m, a
10161026
else:
1017-
linearMatch m, f, a
1027+
m.error InvalidMatch, f, a
10181028
of PtrT, RefT:
10191029
var a = skipModifier(arg.typ)
10201030
let ak = a.typeKind

tests/controlflow/try.expected.nif

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(stmts
22
(call echo "try")
3-
(asgn currexc.0.sys some.exc)
3+
(asgn localErr.0.sysvq0asl some.exc)
44
(goto L11)
55
(goto L20)
66
(lab :L11)

0 commit comments

Comments
 (0)