summary refs log tree commit diff stats
path: root/tests/strictnotnil/tnilcheck_no_warnings.nim
blob: 5ec9bc575a72b27667771f6f3a0309b26d6651ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
discard """
cmd: "nim check --warningAsError:StrictNotNil $file"
action: "compile"
"""

import tables

{.experimental: "strictNotNil".}

type
  Nilable* = ref object
    a*: int
    field*: Nilable
    
  NonNilable* = Nilable not nil

  Nilable2* = nil NonNilable


# proc `[]`(a: Nilable, b: int): Nilable =
#   nil


# Nilable tests



# # test and
proc testAnd(a: Nilable) =
  echo not a.isNil and a.a > 0 # ok


# test else branch and inferring not isNil
# proc testElse(a: Nilable, b: int) =
#   if a.isNil:
#     echo 0
#   else:
#     echo a.a

# test that here we can infer that n can't be nil anymore
proc testNotNilAfterAssign(a: Nilable, b: int) =
  var n = a # a: MaybeNil n: MaybeNil
  if n.isNil: # n: Safe a: MaybeNil
    n = Nilable() # n: Safe a: MaybeNil
  echo n.a # ok

proc callVar(a: var Nilable) =
   a = nil

proc testVarAlias(a: Nilable) = # a: 0 aliasA: 1 {0} {1} 
  var aliasA = a # {0, 1} 0 MaybeNil 1 MaybeNil
  if not a.isNil: # {0, 1} 0 Safe 1 Safe
    callVar(aliasA) # {0, 1} 0 MaybeNil 1 MaybeNil
    # if aliasA stops being in alias: it might be nil, but then a is still not nil
    # if not: it cant be nil as it still points here
    echo a.a # ok 

proc testAliasCheck(a: Nilable) =
  var aliasA = a
  if not a.isNil:
    echo aliasA.a # ok

proc testFieldCheck(a: Nilable) =
  if not a.isNil and not a.field.isNil:
    echo a.field.a # ok

proc testTrackField =
  var a = Nilable(field: Nilable())
  echo a.field.a # ok

proc testNonNilDeref(a: NonNilable) =
  echo a.a # ok

# # not only calls: we can use partitions for dependencies for field aliases
# # so we can detect on change what does this affect or was this mutated between us and the original field


# proc testUniqueHashTree(a: Nilable): Nilable =
#   # TODO what would be a clash
#   var field = 0
#   if not a.isNil and not a.field.isNil:
#     # echo a.field.a
#     echo a[field].a
#   result = Nilable()
  
proc testSeparateShadowingResult(a: Nilable): Nilable =
  result = Nilable()
  if not a.isNil:
    var result: Nilable = nil
  echo result.a


proc testNonNilCString(a: cstring not nil) =
  echo a[0] # ok

proc testNonNilPtr(a: ptr int not nil) =
  echo a[] # ok


# proc testTryCatchDetectNoRaise(a: Nilable) =
#   var other = Nilable()
#   try:
#     other = nil
#     other = a
#     other = Nilable()
#   except:
#     other = nil
#   echo other.a # ok

# proc testTryCatchDetectFinally =
#   var other = Nilable()
#   try:
#     other = nil
#     other = Nilable()
#   except:
#     other = Nilable()
#   finally:
#     other = nil
#   echo other.a # can't deref other: it is nil

# proc testTryCatchDetectNilableWithRaise(b: bool) =
#   var other = Nilable()
#   try:
#     if b:
#       other = nil
#     else:
#       other = Nilable()
#       var other2 = raiseCall()
#   except:
#     echo other.a # ok

#   echo other.a # can't deref a: it might be nil

proc testRaise(a: Nilable) =
  if a.isNil:
    raise newException(ValueError, "a == nil")
  echo a.a # ok

# proc testBlockScope(a: Nilable) =
#   var other = a
#   block:
#     var other = Nilable()
#     echo other.a # ok
#   echo other.a # can't deref other: it might be nil

# # (ask Araq about this: not supported yet) ok we can't really get the nil value from here, so should be ok
# proc testDirectRaiseCall: NonNilable =
#   var a = raiseCall()
#   result = NonNilable()

proc testStmtList =
  var a = Nilable()
  block:
    a = nil
    a = Nilable()
  echo a.a # ok

proc testItemDerefNoWarning(a: var seq[Nilable]) =
  a[0] = Nilable() # good: now .. if we dont track, how do we know 
  echo a[0].a # ok
  var b = 1

  const c = 0
  a[c] = Nilable()
  echo a[0].a # ok

# proc callChange(a: Nilable) =
#   a.field = nil

# proc testCallAlias =
#   var a = Nilable(field: Nilable())
#   callChange(a)
#   echo a.field.a # can't deref a.field, it might be nil

# # proc test10(a: Nilable) =
# #   if not a.isNil and not a.b.isNil:
# #     c_memset(globalA.addr, 0, globalA.sizeOf.csize_t)
# #     globalA = nil
# #     echo a.a # can't deref a: it might be nil

var nilable: Nilable
var withField = Nilable(a: 0, field: Nilable())