tnilcheck_no_warnings.nim 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. discard """
  2. cmd: "nim check --warningAsError:StrictNotNil $file"
  3. action: "compile"
  4. """
  5. import tables
  6. {.experimental: "strictNotNil".}
  7. type
  8. Nilable* = ref object
  9. a*: int
  10. field*: Nilable
  11. NonNilable* = Nilable not nil
  12. Nilable2* = nil NonNilable
  13. # proc `[]`(a: Nilable, b: int): Nilable =
  14. # nil
  15. # Nilable tests
  16. # # test and
  17. proc testAnd(a: Nilable) =
  18. echo not a.isNil and a.a > 0 # ok
  19. # test else branch and inferring not isNil
  20. # proc testElse(a: Nilable, b: int) =
  21. # if a.isNil:
  22. # echo 0
  23. # else:
  24. # echo a.a
  25. # test that here we can infer that n can't be nil anymore
  26. proc testNotNilAfterAssign(a: Nilable, b: int) =
  27. var n = a # a: MaybeNil n: MaybeNil
  28. if n.isNil: # n: Safe a: MaybeNil
  29. n = Nilable() # n: Safe a: MaybeNil
  30. echo n.a # ok
  31. proc callVar(a: var Nilable) =
  32. a = nil
  33. proc testVarAlias(a: Nilable) = # a: 0 aliasA: 1 {0} {1}
  34. var aliasA = a # {0, 1} 0 MaybeNil 1 MaybeNil
  35. if not a.isNil: # {0, 1} 0 Safe 1 Safe
  36. callVar(aliasA) # {0, 1} 0 MaybeNil 1 MaybeNil
  37. # if aliasA stops being in alias: it might be nil, but then a is still not nil
  38. # if not: it cant be nil as it still points here
  39. echo a.a # ok
  40. proc testAliasCheck(a: Nilable) =
  41. var aliasA = a
  42. if not a.isNil:
  43. echo aliasA.a # ok
  44. proc testFieldCheck(a: Nilable) =
  45. if not a.isNil and not a.field.isNil:
  46. echo a.field.a # ok
  47. proc testTrackField =
  48. var a = Nilable(field: Nilable())
  49. echo a.field.a # ok
  50. proc testNonNilDeref(a: NonNilable) =
  51. echo a.a # ok
  52. # # not only calls: we can use partitions for dependencies for field aliases
  53. # # so we can detect on change what does this affect or was this mutated between us and the original field
  54. # proc testUniqueHashTree(a: Nilable): Nilable =
  55. # # TODO what would be a clash
  56. # var field = 0
  57. # if not a.isNil and not a.field.isNil:
  58. # # echo a.field.a
  59. # echo a[field].a
  60. # result = Nilable()
  61. proc testSeparateShadowingResult(a: Nilable): Nilable =
  62. result = Nilable()
  63. if not a.isNil:
  64. var result: Nilable = nil
  65. echo result.a
  66. proc testNonNilCString(a: cstring not nil) =
  67. echo a[0] # ok
  68. proc testNonNilPtr(a: ptr int not nil) =
  69. echo a[] # ok
  70. # proc testTryCatchDetectNoRaise(a: Nilable) =
  71. # var other = Nilable()
  72. # try:
  73. # other = nil
  74. # other = a
  75. # other = Nilable()
  76. # except:
  77. # other = nil
  78. # echo other.a # ok
  79. # proc testTryCatchDetectFinally =
  80. # var other = Nilable()
  81. # try:
  82. # other = nil
  83. # other = Nilable()
  84. # except:
  85. # other = Nilable()
  86. # finally:
  87. # other = nil
  88. # echo other.a # can't deref other: it is nil
  89. # proc testTryCatchDetectNilableWithRaise(b: bool) =
  90. # var other = Nilable()
  91. # try:
  92. # if b:
  93. # other = nil
  94. # else:
  95. # other = Nilable()
  96. # var other2 = raiseCall()
  97. # except:
  98. # echo other.a # ok
  99. # echo other.a # can't deref a: it might be nil
  100. proc testRaise(a: Nilable) =
  101. if a.isNil:
  102. raise newException(ValueError, "a == nil")
  103. echo a.a # ok
  104. # proc testBlockScope(a: Nilable) =
  105. # var other = a
  106. # block:
  107. # var other = Nilable()
  108. # echo other.a # ok
  109. # echo other.a # can't deref other: it might be nil
  110. # # (ask Araq about this: not supported yet) ok we can't really get the nil value from here, so should be ok
  111. # proc testDirectRaiseCall: NonNilable =
  112. # var a = raiseCall()
  113. # result = NonNilable()
  114. proc testStmtList =
  115. var a = Nilable()
  116. block:
  117. a = nil
  118. a = Nilable()
  119. echo a.a # ok
  120. proc testItemDerefNoWarning(a: var seq[Nilable]) =
  121. a[0] = Nilable() # good: now .. if we dont track, how do we know
  122. echo a[0].a # ok
  123. var b = 1
  124. const c = 0
  125. a[c] = Nilable()
  126. echo a[0].a # ok
  127. # proc callChange(a: Nilable) =
  128. # a.field = nil
  129. # proc testCallAlias =
  130. # var a = Nilable(field: Nilable())
  131. # callChange(a)
  132. # echo a.field.a # can't deref a.field, it might be nil
  133. # # proc test10(a: Nilable) =
  134. # # if not a.isNil and not a.b.isNil:
  135. # # c_memset(globalA.addr, 0, globalA.sizeOf.csize_t)
  136. # # globalA = nil
  137. # # echo a.a # can't deref a: it might be nil
  138. var nilable: Nilable
  139. var withField = Nilable(a: 0, field: Nilable())