guards.nim 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements the 'implies' relation for guards.
  10. import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
  11. saturate, modulegraphs, options, lineinfos, int128
  12. when defined(nimPreviewSlimSystem):
  13. import std/assertions
  14. const
  15. someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
  16. mEqStr, mEqSet, mEqCString}
  17. # set excluded here as the semantics are vastly different:
  18. someLe = {mLeI, mLeF64, mLeU, mLeEnum,
  19. mLeCh, mLeB, mLePtr, mLeStr}
  20. someLt = {mLtI, mLtF64, mLtU, mLtEnum,
  21. mLtCh, mLtB, mLtPtr, mLtStr}
  22. someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
  23. someIn = {mInSet}
  24. someHigh = {mHigh}
  25. # we don't list unsigned here because wrap around semantics suck for
  26. # proving anything:
  27. someAdd = {mAddI, mAddF64, mSucc}
  28. someSub = {mSubI, mSubF64, mPred}
  29. someMul = {mMulI, mMulF64}
  30. someDiv = {mDivI, mDivF64}
  31. someMod = {mModI}
  32. someMax = {mMaxI}
  33. someMin = {mMinI}
  34. someBinaryOp = someAdd+someSub+someMul+someMax+someMin
  35. proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
  36. proc isLocation(n: PNode): bool = not n.isValue
  37. proc isLet(n: PNode): bool =
  38. if n.kind == nkSym:
  39. if n.sym.kind in {skLet, skTemp, skForVar}:
  40. result = true
  41. elif n.sym.kind == skParam and skipTypes(n.sym.typ,
  42. abstractInst).kind notin {tyVar}:
  43. result = true
  44. proc isVar(n: PNode): bool =
  45. n.kind == nkSym and n.sym.kind in {skResult, skVar} and
  46. {sfAddrTaken} * n.sym.flags == {}
  47. proc isLetLocation(m: PNode, isApprox: bool): bool =
  48. # consider: 'n[].kind' --> we really need to support 1 deref op even if this
  49. # is technically wrong due to aliasing :-( We could introduce "soft" facts
  50. # for this; this would still be very useful for warnings and also nicely
  51. # solves the 'var' problems. For now we fix this by requiring much more
  52. # restrictive expressions for the 'not nil' checking.
  53. var n = m
  54. var derefs = 0
  55. while true:
  56. case n.kind
  57. of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv:
  58. n = n[0]
  59. of nkDerefExpr:
  60. n = n[0]
  61. inc derefs
  62. of nkHiddenDeref:
  63. n = n[0]
  64. if not isApprox: inc derefs
  65. of nkBracketExpr:
  66. if isConstExpr(n[1]) or isLet(n[1]) or isConstExpr(n[1].skipConv):
  67. n = n[0]
  68. else: return
  69. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  70. n = n[1]
  71. else:
  72. break
  73. result = n.isLet and derefs <= ord(isApprox)
  74. if not result and isApprox:
  75. result = isVar(n)
  76. proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
  77. proc swapArgs(fact: PNode, newOp: PSym): PNode =
  78. result = newNodeI(nkCall, fact.info, 3)
  79. result[0] = newSymNode(newOp)
  80. result[1] = fact[2]
  81. result[2] = fact[1]
  82. proc neg(n: PNode; o: Operators): PNode =
  83. if n == nil: return nil
  84. case n.getMagic
  85. of mNot:
  86. result = n[1]
  87. of someLt:
  88. # not (a < b) == a >= b == b <= a
  89. result = swapArgs(n, o.opLe)
  90. of someLe:
  91. result = swapArgs(n, o.opLt)
  92. of mInSet:
  93. if n[1].kind != nkCurly: return nil
  94. let t = n[2].typ.skipTypes(abstractInst)
  95. result = newNodeI(nkCall, n.info, 3)
  96. result[0] = n[0]
  97. result[2] = n[2]
  98. if t.kind == tyEnum:
  99. var s = newNodeIT(nkCurly, n.info, n[1].typ)
  100. for e in t.n:
  101. let eAsNode = newIntNode(nkIntLit, e.sym.position)
  102. if not inSet(n[1], eAsNode): s.add eAsNode
  103. result[1] = s
  104. #elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
  105. # result[1] = complement(n[1])
  106. else:
  107. # not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4
  108. # XXX todo
  109. result = nil
  110. of mOr:
  111. # not (a or b) --> not a and not b
  112. let
  113. a = n[1].neg(o)
  114. b = n[2].neg(o)
  115. if a != nil and b != nil:
  116. result = newNodeI(nkCall, n.info, 3)
  117. result[0] = newSymNode(o.opAnd)
  118. result[1] = a
  119. result[2] = b
  120. elif a != nil:
  121. result = a
  122. elif b != nil:
  123. result = b
  124. else:
  125. # leave not (a == 4) as it is
  126. result = newNodeI(nkCall, n.info, 2)
  127. result[0] = newSymNode(o.opNot)
  128. result[1] = n
  129. proc buildCall*(op: PSym; a: PNode): PNode =
  130. result = newNodeI(nkCall, a.info, 2)
  131. result[0] = newSymNode(op)
  132. result[1] = a
  133. proc buildCall*(op: PSym; a, b: PNode): PNode =
  134. result = newNodeI(nkInfix, a.info, 3)
  135. result[0] = newSymNode(op)
  136. result[1] = a
  137. result[2] = b
  138. proc `|+|`(a, b: PNode): PNode =
  139. result = copyNode(a)
  140. if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |+| b.intVal
  141. else: result.floatVal = a.floatVal + b.floatVal
  142. proc `|-|`(a, b: PNode): PNode =
  143. result = copyNode(a)
  144. if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |-| b.intVal
  145. else: result.floatVal = a.floatVal - b.floatVal
  146. proc `|*|`(a, b: PNode): PNode =
  147. result = copyNode(a)
  148. if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |*| b.intVal
  149. else: result.floatVal = a.floatVal * b.floatVal
  150. proc `|div|`(a, b: PNode): PNode =
  151. result = copyNode(a)
  152. if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal
  153. else: result.floatVal = a.floatVal / b.floatVal
  154. proc negate(a, b, res: PNode; o: Operators): PNode =
  155. if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt):
  156. var b = copyNode(b)
  157. b.intVal = -b.intVal
  158. if a.kind in {nkCharLit..nkUInt64Lit}:
  159. b.intVal = b.intVal |+| a.intVal
  160. result = b
  161. else:
  162. result = buildCall(o.opAdd, a, b)
  163. elif b.kind in {nkFloatLit..nkFloat64Lit}:
  164. var b = copyNode(b)
  165. b.floatVal = -b.floatVal
  166. result = buildCall(o.opAdd, a, b)
  167. else:
  168. result = res
  169. proc zero(): PNode = nkIntLit.newIntNode(0)
  170. proc one(): PNode = nkIntLit.newIntNode(1)
  171. proc minusOne(): PNode = nkIntLit.newIntNode(-1)
  172. proc lowBound*(conf: ConfigRef; x: PNode): PNode =
  173. result = nkIntLit.newIntNode(firstOrd(conf, x.typ))
  174. result.info = x.info
  175. proc highBound*(conf: ConfigRef; x: PNode; o: Operators): PNode =
  176. let typ = x.typ.skipTypes(abstractInst)
  177. result = if typ.kind == tyArray:
  178. nkIntLit.newIntNode(lastOrd(conf, typ))
  179. elif typ.kind == tySequence and x.kind == nkSym and
  180. x.sym.kind == skConst:
  181. nkIntLit.newIntNode(x.sym.astdef.len-1)
  182. else:
  183. o.opAdd.buildCall(o.opLen.buildCall(x), minusOne())
  184. result.info = x.info
  185. proc reassociation(n: PNode; o: Operators): PNode =
  186. result = n
  187. # (foo+5)+5 --> foo+10; same for '*'
  188. case result.getMagic
  189. of someAdd:
  190. if result[2].isValue and
  191. result[1].getMagic in someAdd and result[1][2].isValue:
  192. result = o.opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
  193. if result[2].intVal == 0:
  194. result = result[1]
  195. of someMul:
  196. if result[2].isValue and
  197. result[1].getMagic in someMul and result[1][2].isValue:
  198. result = o.opMul.buildCall(result[1][1], result[1][2] |*| result[2])
  199. if result[2].intVal == 1:
  200. result = result[1]
  201. elif result[2].intVal == 0:
  202. result = zero()
  203. else: discard
  204. proc pred(n: PNode): PNode =
  205. if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
  206. result = copyNode(n)
  207. dec result.intVal
  208. else:
  209. result = n
  210. proc buildLe*(o: Operators; a, b: PNode): PNode =
  211. result = o.opLe.buildCall(a, b)
  212. proc canon*(n: PNode; o: Operators): PNode =
  213. if n.safeLen >= 1:
  214. result = shallowCopy(n)
  215. for i in 0..<n.len:
  216. result[i] = canon(n[i], o)
  217. elif n.kind == nkSym and n.sym.kind == skLet and
  218. n.sym.astdef.getMagic in (someEq + someAdd + someMul + someMin +
  219. someMax + someHigh + someSub + someLen + someDiv):
  220. result = n.sym.astdef.copyTree
  221. else:
  222. result = n
  223. case result.getMagic
  224. of someEq, someAdd, someMul, someMin, someMax:
  225. # these are symmetric; put value as last:
  226. if result[1].isValue and not result[2].isValue:
  227. result = swapArgs(result, result[0].sym)
  228. # (4 + foo) + 2 --> (foo + 4) + 2
  229. of someHigh:
  230. # high == len+(-1)
  231. result = o.opAdd.buildCall(o.opLen.buildCall(result[1]), minusOne())
  232. of someSub:
  233. # x - 4 --> x + (-4)
  234. result = negate(result[1], result[2], result, o)
  235. of someLen:
  236. result[0] = o.opLen.newSymNode
  237. of someLt - {mLtF64}:
  238. # x < y same as x <= y-1:
  239. let y = n[2].canon(o)
  240. let p = pred(y)
  241. let minus = if p != y: p else: o.opAdd.buildCall(y, minusOne()).canon(o)
  242. result = o.opLe.buildCall(n[1].canon(o), minus)
  243. else: discard
  244. result = skipConv(result)
  245. result = reassociation(result, o)
  246. # most important rule: (x-4) <= a.len --> x <= a.len+4
  247. case result.getMagic
  248. of someLe:
  249. let x = result[1]
  250. let y = result[2]
  251. if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and
  252. isLetLocation(x[1], true):
  253. case x.getMagic
  254. of someSub:
  255. result = buildCall(result[0].sym, x[1],
  256. reassociation(o.opAdd.buildCall(y, x[2]), o))
  257. of someAdd:
  258. # Rule A:
  259. let plus = negate(y, x[2], nil, o).reassociation(o)
  260. if plus != nil: result = buildCall(result[0].sym, x[1], plus)
  261. else: discard
  262. elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
  263. isLetLocation(y[1], true):
  264. # a.len < x-3
  265. case y.getMagic
  266. of someSub:
  267. result = buildCall(result[0].sym, y[1],
  268. reassociation(o.opAdd.buildCall(x, y[2]), o))
  269. of someAdd:
  270. let plus = negate(x, y[2], nil, o).reassociation(o)
  271. # ensure that Rule A will not trigger afterwards with the
  272. # additional 'not isLetLocation' constraint:
  273. if plus != nil and not isLetLocation(x, true):
  274. result = buildCall(result[0].sym, plus, y[1])
  275. else: discard
  276. elif x.isValue and y.getMagic in someAdd and y[2].kind == x.kind:
  277. # 0 <= a.len + 3
  278. # -3 <= a.len
  279. result[1] = x |-| y[2]
  280. result[2] = y[1]
  281. elif x.isValue and y.getMagic in someSub and y[2].kind == x.kind:
  282. # 0 <= a.len - 3
  283. # 3 <= a.len
  284. result[1] = x |+| y[2]
  285. result[2] = y[1]
  286. else: discard
  287. proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
  288. canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o)
  289. proc usefulFact(n: PNode; o: Operators): PNode =
  290. case n.getMagic
  291. of someEq:
  292. if skipConv(n[2]).kind == nkNilLit and (
  293. isLetLocation(n[1], false) or isVar(n[1])):
  294. result = o.opIsNil.buildCall(n[1])
  295. else:
  296. if isLetLocation(n[1], true) or isLetLocation(n[2], true):
  297. # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
  298. result = n
  299. elif n[1].getMagic in someLen or n[2].getMagic in someLen:
  300. result = n
  301. of someLe+someLt:
  302. if isLetLocation(n[1], true) or isLetLocation(n[2], true):
  303. # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
  304. result = n
  305. elif n[1].getMagic in someLen or n[2].getMagic in someLen:
  306. # XXX Rethink this whole idea of 'usefulFact' for semparallel
  307. result = n
  308. of mIsNil:
  309. if isLetLocation(n[1], false) or isVar(n[1]):
  310. result = n
  311. of someIn:
  312. if isLetLocation(n[1], true):
  313. result = n
  314. of mAnd:
  315. let
  316. a = usefulFact(n[1], o)
  317. b = usefulFact(n[2], o)
  318. if a != nil and b != nil:
  319. result = newNodeI(nkCall, n.info, 3)
  320. result[0] = newSymNode(o.opAnd)
  321. result[1] = a
  322. result[2] = b
  323. elif a != nil:
  324. result = a
  325. elif b != nil:
  326. result = b
  327. of mNot:
  328. let a = usefulFact(n[1], o)
  329. if a != nil:
  330. result = a.neg(o)
  331. of mOr:
  332. # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
  333. # with that knowledge...
  334. # DeMorgan helps a little though:
  335. # not a or not b --> not (a and b)
  336. # (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
  337. # not (x != 3 and y != 2)
  338. let
  339. a = usefulFact(n[1], o).neg(o)
  340. b = usefulFact(n[2], o).neg(o)
  341. if a != nil and b != nil:
  342. result = newNodeI(nkCall, n.info, 3)
  343. result[0] = newSymNode(o.opAnd)
  344. result[1] = a
  345. result[2] = b
  346. result = result.neg(o)
  347. elif n.kind == nkSym and n.sym.kind == skLet:
  348. # consider:
  349. # let a = 2 < x
  350. # if a:
  351. # ...
  352. # We make can easily replace 'a' by '2 < x' here:
  353. if n.sym.astdef != nil:
  354. result = usefulFact(n.sym.astdef, o)
  355. elif n.kind == nkStmtListExpr:
  356. result = usefulFact(n.lastSon, o)
  357. type
  358. TModel* = object
  359. s*: seq[PNode] # the "knowledge base"
  360. g*: ModuleGraph
  361. beSmart*: bool
  362. proc addFact*(m: var TModel, nn: PNode) =
  363. let n = usefulFact(nn, m.g.operators)
  364. if n != nil:
  365. if not m.beSmart:
  366. m.s.add n
  367. else:
  368. let c = canon(n, m.g.operators)
  369. if c.getMagic == mAnd:
  370. addFact(m, c[1])
  371. addFact(m, c[2])
  372. else:
  373. m.s.add c
  374. proc addFactNeg*(m: var TModel, n: PNode) =
  375. let n = n.neg(m.g.operators)
  376. if n != nil: addFact(m, n)
  377. proc sameOpr(a, b: PSym): bool =
  378. case a.magic
  379. of someEq: result = b.magic in someEq
  380. of someLe: result = b.magic in someLe
  381. of someLt: result = b.magic in someLt
  382. of someLen: result = b.magic in someLen
  383. of someAdd: result = b.magic in someAdd
  384. of someSub: result = b.magic in someSub
  385. of someMul: result = b.magic in someMul
  386. of someDiv: result = b.magic in someDiv
  387. else: result = a == b
  388. proc sameTree*(a, b: PNode): bool =
  389. result = false
  390. if a == b:
  391. result = true
  392. elif a != nil and b != nil and a.kind == b.kind:
  393. case a.kind
  394. of nkSym:
  395. result = a.sym == b.sym
  396. if not result and a.sym.magic != mNone:
  397. result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym)
  398. of nkIdent: result = a.ident.id == b.ident.id
  399. of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
  400. of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
  401. of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
  402. of nkType: result = a.typ == b.typ
  403. of nkEmpty, nkNilLit: result = true
  404. else:
  405. if a.len == b.len:
  406. for i in 0..<a.len:
  407. if not sameTree(a[i], b[i]): return
  408. result = true
  409. proc hasSubTree(n, x: PNode): bool =
  410. if n.sameTree(x): result = true
  411. else:
  412. case n.kind
  413. of nkEmpty..nkNilLit:
  414. result = n.sameTree(x)
  415. of nkFormalParams:
  416. discard
  417. else:
  418. for i in 0..<n.len:
  419. if hasSubTree(n[i], x): return true
  420. proc invalidateFacts*(s: var seq[PNode], n: PNode) =
  421. # We are able to guard local vars (as opposed to 'let' variables)!
  422. # 'while p != nil: f(p); p = p.next'
  423. # This is actually quite easy to do:
  424. # Re-assignments (incl. pass to a 'var' param) trigger an invalidation
  425. # of every fact that contains 'v'.
  426. #
  427. # if x < 4:
  428. # if y < 5
  429. # x = unknown()
  430. # # we invalidate 'x' here but it's known that x >= 4
  431. # # for the else anyway
  432. # else:
  433. # echo x
  434. #
  435. # The same mechanism could be used for more complex data stored on the heap;
  436. # procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
  437. # could CSE these expressions then and help C's optimizer.
  438. for i in 0..high(s):
  439. if s[i] != nil and s[i].hasSubTree(n): s[i] = nil
  440. proc invalidateFacts*(m: var TModel, n: PNode) =
  441. invalidateFacts(m.s, n)
  442. proc valuesUnequal(a, b: PNode): bool =
  443. if a.isValue and b.isValue:
  444. result = not sameValue(a, b)
  445. proc impliesEq(fact, eq: PNode): TImplication =
  446. let (loc, val) = if isLocation(eq[1]): (1, 2) else: (2, 1)
  447. case fact[0].sym.magic
  448. of someEq:
  449. if sameTree(fact[1], eq[loc]):
  450. # this is not correct; consider: a == b; a == 1 --> unknown!
  451. if sameTree(fact[2], eq[val]): result = impYes
  452. elif valuesUnequal(fact[2], eq[val]): result = impNo
  453. elif sameTree(fact[2], eq[loc]):
  454. if sameTree(fact[1], eq[val]): result = impYes
  455. elif valuesUnequal(fact[1], eq[val]): result = impNo
  456. of mInSet:
  457. # remember: mInSet is 'contains' so the set comes first!
  458. if sameTree(fact[2], eq[loc]) and isValue(eq[val]):
  459. if inSet(fact[1], eq[val]): result = impYes
  460. else: result = impNo
  461. of mNot, mOr, mAnd: assert(false, "impliesEq")
  462. else: discard
  463. proc leImpliesIn(x, c, aSet: PNode): TImplication =
  464. if c.kind in {nkCharLit..nkUInt64Lit}:
  465. # fact: x <= 4; question x in {56}?
  466. # --> true if every value <= 4 is in the set {56}
  467. #
  468. var value = newIntNode(c.kind, firstOrd(nil, x.typ))
  469. # don't iterate too often:
  470. if c.intVal - value.intVal < 1000:
  471. var i, pos, neg: int
  472. while value.intVal <= c.intVal:
  473. if inSet(aSet, value): inc pos
  474. else: inc neg
  475. inc i; inc value.intVal
  476. if pos == i: result = impYes
  477. elif neg == i: result = impNo
  478. proc geImpliesIn(x, c, aSet: PNode): TImplication =
  479. if c.kind in {nkCharLit..nkUInt64Lit}:
  480. # fact: x >= 4; question x in {56}?
  481. # --> true iff every value >= 4 is in the set {56}
  482. #
  483. var value = newIntNode(c.kind, c.intVal)
  484. let max = lastOrd(nil, x.typ)
  485. # don't iterate too often:
  486. if max - getInt(value) < toInt128(1000):
  487. var i, pos, neg: int
  488. while value.intVal <= max:
  489. if inSet(aSet, value): inc pos
  490. else: inc neg
  491. inc i; inc value.intVal
  492. if pos == i: result = impYes
  493. elif neg == i: result = impNo
  494. proc compareSets(a, b: PNode): TImplication =
  495. if equalSets(nil, a, b): result = impYes
  496. elif intersectSets(nil, a, b).len == 0: result = impNo
  497. proc impliesIn(fact, loc, aSet: PNode): TImplication =
  498. case fact[0].sym.magic
  499. of someEq:
  500. if sameTree(fact[1], loc):
  501. if inSet(aSet, fact[2]): result = impYes
  502. else: result = impNo
  503. elif sameTree(fact[2], loc):
  504. if inSet(aSet, fact[1]): result = impYes
  505. else: result = impNo
  506. of mInSet:
  507. if sameTree(fact[2], loc):
  508. result = compareSets(fact[1], aSet)
  509. of someLe:
  510. if sameTree(fact[1], loc):
  511. result = leImpliesIn(fact[1], fact[2], aSet)
  512. elif sameTree(fact[2], loc):
  513. result = geImpliesIn(fact[2], fact[1], aSet)
  514. of someLt:
  515. if sameTree(fact[1], loc):
  516. result = leImpliesIn(fact[1], fact[2].pred, aSet)
  517. elif sameTree(fact[2], loc):
  518. # 4 < x --> 3 <= x
  519. result = geImpliesIn(fact[2], fact[1].pred, aSet)
  520. of mNot, mOr, mAnd: assert(false, "impliesIn")
  521. else: discard
  522. proc valueIsNil(n: PNode): TImplication =
  523. if n.kind == nkNilLit: impYes
  524. elif n.kind in {nkStrLit..nkTripleStrLit, nkBracket, nkObjConstr}: impNo
  525. else: impUnknown
  526. proc impliesIsNil(fact, eq: PNode): TImplication =
  527. case fact[0].sym.magic
  528. of mIsNil:
  529. if sameTree(fact[1], eq[1]):
  530. result = impYes
  531. of someEq:
  532. if sameTree(fact[1], eq[1]):
  533. result = valueIsNil(fact[2].skipConv)
  534. elif sameTree(fact[2], eq[1]):
  535. result = valueIsNil(fact[1].skipConv)
  536. of mNot, mOr, mAnd: assert(false, "impliesIsNil")
  537. else: discard
  538. proc impliesGe(fact, x, c: PNode): TImplication =
  539. assert isLocation(x)
  540. case fact[0].sym.magic
  541. of someEq:
  542. if sameTree(fact[1], x):
  543. if isValue(fact[2]) and isValue(c):
  544. # fact: x = 4; question x >= 56? --> true iff 4 >= 56
  545. if leValue(c, fact[2]): result = impYes
  546. else: result = impNo
  547. elif sameTree(fact[2], x):
  548. if isValue(fact[1]) and isValue(c):
  549. if leValue(c, fact[1]): result = impYes
  550. else: result = impNo
  551. of someLt:
  552. if sameTree(fact[1], x):
  553. if isValue(fact[2]) and isValue(c):
  554. # fact: x < 4; question N <= x? --> false iff N <= 4
  555. if leValue(fact[2], c): result = impNo
  556. # fact: x < 4; question 2 <= x? --> we don't know
  557. elif sameTree(fact[2], x):
  558. # fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
  559. if isValue(fact[1]) and isValue(c):
  560. if leValue(c.pred, fact[1]): result = impYes
  561. of someLe:
  562. if sameTree(fact[1], x):
  563. if isValue(fact[2]) and isValue(c):
  564. # fact: x <= 4; question x >= 56? --> false iff 4 <= 56
  565. if leValue(fact[2], c): result = impNo
  566. # fact: x <= 4; question x >= 2? --> we don't know
  567. elif sameTree(fact[2], x):
  568. # fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
  569. if isValue(fact[1]) and isValue(c):
  570. if leValue(c, fact[1]): result = impYes
  571. of mNot, mOr, mAnd: assert(false, "impliesGe")
  572. else: discard
  573. proc impliesLe(fact, x, c: PNode): TImplication =
  574. if not isLocation(x):
  575. if c.isValue:
  576. if leValue(x, x): return impYes
  577. else: return impNo
  578. return impliesGe(fact, c, x)
  579. case fact[0].sym.magic
  580. of someEq:
  581. if sameTree(fact[1], x):
  582. if isValue(fact[2]) and isValue(c):
  583. # fact: x = 4; question x <= 56? --> true iff 4 <= 56
  584. if leValue(fact[2], c): result = impYes
  585. else: result = impNo
  586. elif sameTree(fact[2], x):
  587. if isValue(fact[1]) and isValue(c):
  588. if leValue(fact[1], c): result = impYes
  589. else: result = impNo
  590. of someLt:
  591. if sameTree(fact[1], x):
  592. if isValue(fact[2]) and isValue(c):
  593. # fact: x < 4; question x <= N? --> true iff N-1 <= 4
  594. if leValue(fact[2], c.pred): result = impYes
  595. # fact: x < 4; question x <= 2? --> we don't know
  596. elif sameTree(fact[2], x):
  597. # fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
  598. if isValue(fact[1]) and isValue(c):
  599. if leValue(c, fact[1]): result = impNo
  600. of someLe:
  601. if sameTree(fact[1], x):
  602. if isValue(fact[2]) and isValue(c):
  603. # fact: x <= 4; question x <= 56? --> true iff 4 <= 56
  604. if leValue(fact[2], c): result = impYes
  605. # fact: x <= 4; question x <= 2? --> we don't know
  606. elif sameTree(fact[2], x):
  607. # fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
  608. if isValue(fact[1]) and isValue(c):
  609. if leValue(c, fact[1].pred): result = impNo
  610. of mNot, mOr, mAnd: assert(false, "impliesLe")
  611. else: discard
  612. proc impliesLt(fact, x, c: PNode): TImplication =
  613. # x < 3 same as x <= 2:
  614. let p = c.pred
  615. if p != c:
  616. result = impliesLe(fact, x, p)
  617. else:
  618. # 4 < x same as 3 <= x
  619. let q = x.pred
  620. if q != x:
  621. result = impliesLe(fact, q, c)
  622. proc `~`(x: TImplication): TImplication =
  623. case x
  624. of impUnknown: impUnknown
  625. of impNo: impYes
  626. of impYes: impNo
  627. proc factImplies(fact, prop: PNode): TImplication =
  628. case fact.getMagic
  629. of mNot:
  630. # Consider:
  631. # enum nkBinary, nkTernary, nkStr
  632. # fact: not (k <= nkBinary)
  633. # question: k in {nkStr}
  634. # --> 'not' for facts is entirely different than 'not' for questions!
  635. # it's provably wrong if every value > 4 is in the set {56}
  636. # That's because we compute the implication and 'a -> not b' cannot
  637. # be treated the same as 'not a -> b'
  638. # (not a) -> b compute as not (a -> b) ???
  639. # == not a or not b == not (a and b)
  640. let arg = fact[1]
  641. case arg.getMagic
  642. of mIsNil, mEqRef:
  643. return ~factImplies(arg, prop)
  644. of mAnd:
  645. # not (a and b) means not a or not b:
  646. # a or b --> both need to imply 'prop'
  647. let a = factImplies(arg[1], prop)
  648. let b = factImplies(arg[2], prop)
  649. if a == b: return ~a
  650. return impUnknown
  651. else:
  652. return impUnknown
  653. of mAnd:
  654. result = factImplies(fact[1], prop)
  655. if result != impUnknown: return result
  656. return factImplies(fact[2], prop)
  657. else: discard
  658. case prop[0].sym.magic
  659. of mNot: result = ~fact.factImplies(prop[1])
  660. of mIsNil: result = impliesIsNil(fact, prop)
  661. of someEq: result = impliesEq(fact, prop)
  662. of someLe: result = impliesLe(fact, prop[1], prop[2])
  663. of someLt: result = impliesLt(fact, prop[1], prop[2])
  664. of mInSet: result = impliesIn(fact, prop[2], prop[1])
  665. else: result = impUnknown
  666. proc doesImply*(facts: TModel, prop: PNode): TImplication =
  667. assert prop.kind in nkCallKinds
  668. for f in facts.s:
  669. # facts can be invalidated, in which case they are 'nil':
  670. if not f.isNil:
  671. result = f.factImplies(prop)
  672. if result != impUnknown: return
  673. proc impliesNotNil*(m: TModel, arg: PNode): TImplication =
  674. result = doesImply(m, m.g.operators.opIsNil.buildCall(arg).neg(m.g.operators))
  675. proc simpleSlice*(a, b: PNode): BiggestInt =
  676. # returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched
  677. # as if it is (i+0)..(i+0).
  678. if guards.sameTree(a, b):
  679. if a.getMagic in someAdd and a[2].kind in {nkCharLit..nkUInt64Lit}:
  680. result = a[2].intVal
  681. else:
  682. result = 0
  683. else:
  684. result = -1
  685. template isMul(x): untyped = x.getMagic in someMul
  686. template isDiv(x): untyped = x.getMagic in someDiv
  687. template isAdd(x): untyped = x.getMagic in someAdd
  688. template isSub(x): untyped = x.getMagic in someSub
  689. template isVal(x): untyped = x.kind in {nkCharLit..nkUInt64Lit}
  690. template isIntVal(x, y): untyped = x.intVal == y
  691. import macros
  692. macro `=~`(x: PNode, pat: untyped): bool =
  693. proc m(x, pat, conds: NimNode) =
  694. case pat.kind
  695. of nnkInfix:
  696. case $pat[0]
  697. of "*": conds.add getAst(isMul(x))
  698. of "/": conds.add getAst(isDiv(x))
  699. of "+": conds.add getAst(isAdd(x))
  700. of "-": conds.add getAst(isSub(x))
  701. else:
  702. error("invalid pattern")
  703. m(newTree(nnkBracketExpr, x, newLit(1)), pat[1], conds)
  704. m(newTree(nnkBracketExpr, x, newLit(2)), pat[2], conds)
  705. of nnkPar:
  706. if pat.len == 1:
  707. m(x, pat[0], conds)
  708. else:
  709. error("invalid pattern")
  710. of nnkIdent:
  711. let c = newTree(nnkStmtListExpr, newLetStmt(pat, x))
  712. conds.add c
  713. # XXX why is this 'isVal(pat)' and not 'isVal(x)'?
  714. if ($pat)[^1] == 'c': c.add(getAst(isVal(x)))
  715. else: c.add bindSym"true"
  716. of nnkIntLit:
  717. conds.add(getAst(isIntVal(x, pat.intVal)))
  718. else:
  719. error("invalid pattern")
  720. var conds = newTree(nnkBracket)
  721. m(x, pat, conds)
  722. result = nestList(ident"and", conds)
  723. proc isMinusOne(n: PNode): bool =
  724. n.kind in {nkCharLit..nkUInt64Lit} and n.intVal == -1
  725. proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
  726. proc ple(m: TModel; a, b: PNode): TImplication =
  727. template `<=?`(a,b): untyped = ple(m,a,b) == impYes
  728. template `>=?`(a,b): untyped = ple(m, nkIntLit.newIntNode(b), a) == impYes
  729. # 0 <= 3
  730. if a.isValue and b.isValue:
  731. return if leValue(a, b): impYes else: impNo
  732. # use type information too: x <= 4 iff high(x) <= 4
  733. if b.isValue and a.typ != nil and a.typ.isOrdinalType:
  734. if lastOrd(nil, a.typ) <= b.intVal: return impYes
  735. # 3 <= x iff low(x) <= 3
  736. if a.isValue and b.typ != nil and b.typ.isOrdinalType:
  737. if a.intVal <= firstOrd(nil, b.typ): return impYes
  738. # x <= x
  739. if sameTree(a, b): return impYes
  740. # 0 <= x.len
  741. if b.getMagic in someLen and a.isValue:
  742. if a.intVal <= 0: return impYes
  743. # x <= y+c if 0 <= c and x <= y
  744. # x <= y+(-c) if c <= 0 and y >= x
  745. if b.getMagic in someAdd:
  746. if zero() <=? b[2] and a <=? b[1]: return impYes
  747. # x <= y-c if x+c <= y
  748. if b[2] <=? zero() and (canon(m.g.operators.opSub.buildCall(a, b[2]), m.g.operators) <=? b[1]):
  749. return impYes
  750. # x+c <= y if c <= 0 and x <= y
  751. if a.getMagic in someAdd and a[2] <=? zero() and a[1] <=? b: return impYes
  752. # x <= y*c if 1 <= c and x <= y and 0 <= y
  753. if b.getMagic in someMul:
  754. if a <=? b[1] and one() <=? b[2] and zero() <=? b[1]: return impYes
  755. if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and
  756. a[1][2].isValue:
  757. # simplify (x div 4) * 2 <= y to x div (c div d) <= y
  758. if ple(m, buildCall(m.g.operators.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
  759. return impYes
  760. # x*3 + x == x*4. It follows that:
  761. # x*3 + y <= x*4 if y <= x and 3 <= 4
  762. if a =~ x*dc + y and b =~ x2*ec:
  763. if sameTree(x, x2):
  764. let ec1 = m.g.operators.opAdd.buildCall(ec, minusOne())
  765. if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x:
  766. return impYes
  767. elif a =~ x*dc and b =~ x2*ec + y:
  768. #echo "BUG cam ehrer e ", a, " <=? ", b
  769. if sameTree(x, x2):
  770. let ec1 = m.g.operators.opAdd.buildCall(ec, minusOne())
  771. if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero():
  772. return impYes
  773. # x+c <= x+d if c <= d. Same for *, - etc.
  774. if a.getMagic in someBinaryOp and a.getMagic == b.getMagic:
  775. if sameTree(a[1], b[1]) and a[2] <=? b[2]: return impYes
  776. elif sameTree(a[2], b[2]) and a[1] <=? b[1]: return impYes
  777. # x div c <= y if 1 <= c and 0 <= y and x <= y:
  778. if a.getMagic in someDiv:
  779. if one() <=? a[2] and zero() <=? b and a[1] <=? b: return impYes
  780. # x div c <= x div d if d <= c
  781. if b.getMagic in someDiv:
  782. if sameTree(a[1], b[1]) and b[2] <=? a[2]: return impYes
  783. # x div z <= x - 1 if z <= x
  784. if a[2].isValue and b.getMagic in someAdd and b[2].isMinusOne:
  785. if a[2] <=? a[1] and sameTree(a[1], b[1]): return impYes
  786. # slightly subtle:
  787. # x <= max(y, z) iff x <= y or x <= z
  788. # note that 'x <= max(x, z)' is a special case of the above rule
  789. if b.getMagic in someMax:
  790. if a <=? b[1] or a <=? b[2]: return impYes
  791. # min(x, y) <= z iff x <= z or y <= z
  792. if a.getMagic in someMin:
  793. if a[1] <=? b or a[2] <=? b: return impYes
  794. # use the knowledge base:
  795. return pleViaModel(m, a, b)
  796. #return doesImply(m, o.opLe.buildCall(a, b))
  797. type TReplacements = seq[tuple[a, b: PNode]]
  798. proc replaceSubTree(n, x, by: PNode): PNode =
  799. if sameTree(n, x):
  800. result = by
  801. elif hasSubTree(n, x):
  802. result = shallowCopy(n)
  803. for i in 0..n.safeLen-1:
  804. result[i] = replaceSubTree(n[i], x, by)
  805. else:
  806. result = n
  807. proc applyReplacements(n: PNode; rep: TReplacements): PNode =
  808. result = n
  809. for x in rep: result = result.replaceSubTree(x.a, x.b)
  810. proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
  811. # now check for inferrable facts: a <= b and b <= c implies a <= c
  812. for i in 0..m.s.high:
  813. let fact = m.s[i]
  814. if fact != nil and fact.getMagic in someLe:
  815. # mark as used:
  816. m.s[i] = nil
  817. # i <= len-100
  818. # i <=? len-1
  819. # --> true if (len-100) <= (len-1)
  820. let x = fact[1]
  821. let y = fact[2]
  822. # x <= y.
  823. # Question: x <= b? True iff y <= b.
  824. if sameTree(x, a):
  825. if ple(m, y, b) == impYes: return impYes
  826. if y.getMagic in someAdd and b.getMagic in someAdd and sameTree(y[1], b[1]):
  827. if ple(m, b[2], y[2]) == impYes:
  828. return impYes
  829. # x <= y implies a <= b if a <= x and y <= b
  830. if ple(m, a, x) == impYes:
  831. if ple(m, y, b) == impYes:
  832. return impYes
  833. #if pleViaModelRec(m, y, b): return impYes
  834. # fact: 16 <= i
  835. # x y
  836. # question: i <= 15? no!
  837. result = impliesLe(fact, a, b)
  838. if result != impUnknown:
  839. return result
  840. when false:
  841. # given: x <= y; y==a; x <= a this means: a <= b if x <= b
  842. if sameTree(y, a):
  843. result = ple(m, b, x)
  844. if result != impUnknown:
  845. return result
  846. proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
  847. # compute replacements:
  848. var replacements: TReplacements = @[]
  849. for fact in model.s:
  850. if fact != nil and fact.getMagic in someEq:
  851. let a = fact[1]
  852. let b = fact[2]
  853. if a.kind == nkSym: replacements.add((a,b))
  854. else: replacements.add((b,a))
  855. var m: TModel
  856. var a = aa
  857. var b = bb
  858. if replacements.len > 0:
  859. m.s = @[]
  860. m.g = model.g
  861. # make the other facts consistent:
  862. for fact in model.s:
  863. if fact != nil and fact.getMagic notin someEq:
  864. # XXX 'canon' should not be necessary here, but it is
  865. m.s.add applyReplacements(fact, replacements).canon(m.g.operators)
  866. a = applyReplacements(aa, replacements)
  867. b = applyReplacements(bb, replacements)
  868. else:
  869. # we have to make a copy here, because the model will be modified:
  870. m = model
  871. result = pleViaModelRec(m, a, b)
  872. proc proveLe*(m: TModel; a, b: PNode): TImplication =
  873. let x = canon(m.g.operators.opLe.buildCall(a, b), m.g.operators)
  874. #echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2])
  875. result = ple(m, x[1], x[2])
  876. if result == impUnknown:
  877. # try an alternative: a <= b iff not (b < a) iff not (b+1 <= a):
  878. let y = canon(m.g.operators.opLe.buildCall(m.g.operators.opAdd.buildCall(b, one()), a), m.g.operators)
  879. result = ~ple(m, y[1], y[2])
  880. proc addFactLe*(m: var TModel; a, b: PNode) =
  881. m.s.add canon(m.g.operators.opLe.buildCall(a, b), m.g.operators)
  882. proc addFactLt*(m: var TModel; a, b: PNode) =
  883. let bb = m.g.operators.opAdd.buildCall(b, minusOne())
  884. addFactLe(m, a, bb)
  885. proc settype(n: PNode): PType =
  886. result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
  887. var idgen: IdGenerator
  888. addSonSkipIntLit(result, n.typ, idgen)
  889. proc buildOf(it, loc: PNode; o: Operators): PNode =
  890. var s = newNodeI(nkCurly, it.info, it.len-1)
  891. s.typ = settype(loc)
  892. for i in 0..<it.len-1: s[i] = it[i]
  893. result = newNodeI(nkCall, it.info, 3)
  894. result[0] = newSymNode(o.opContains)
  895. result[1] = s
  896. result[2] = loc
  897. proc buildElse(n: PNode; o: Operators): PNode =
  898. var s = newNodeIT(nkCurly, n.info, settype(n[0]))
  899. for i in 1..<n.len-1:
  900. let branch = n[i]
  901. assert branch.kind != nkElse
  902. if branch.kind == nkOfBranch:
  903. for j in 0..<branch.len-1:
  904. s.add(branch[j])
  905. result = newNodeI(nkCall, n.info, 3)
  906. result[0] = newSymNode(o.opContains)
  907. result[1] = s
  908. result[2] = n[0]
  909. proc addDiscriminantFact*(m: var TModel, n: PNode) =
  910. var fact = newNodeI(nkCall, n.info, 3)
  911. fact[0] = newSymNode(m.g.operators.opEq)
  912. fact[1] = n[0]
  913. fact[2] = n[1]
  914. m.s.add fact
  915. proc addAsgnFact*(m: var TModel, key, value: PNode) =
  916. var fact = newNodeI(nkCall, key.info, 3)
  917. fact[0] = newSymNode(m.g.operators.opEq)
  918. fact[1] = key
  919. fact[2] = value
  920. m.s.add fact
  921. proc sameSubexprs*(m: TModel; a, b: PNode): bool =
  922. # This should be used to check whether two *path expressions* refer to the
  923. # same memory location according to 'm'. This is tricky:
  924. # lock a[i].guard:
  925. # ...
  926. # access a[i].guarded
  927. #
  928. # Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'.
  929. # However, nil checking requires exactly the same mechanism! But for now
  930. # we simply use sameTree and live with the unsoundness of the analysis.
  931. var check = newNodeI(nkCall, a.info, 3)
  932. check[0] = newSymNode(m.g.operators.opEq)
  933. check[1] = a
  934. check[2] = b
  935. result = m.doesImply(check) == impYes
  936. proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
  937. let branch = n[i]
  938. if branch.kind == nkOfBranch:
  939. m.s.add buildOf(branch, n[0], m.g.operators)
  940. else:
  941. m.s.add n.buildElse(m.g.operators).neg(m.g.operators)
  942. proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
  943. if check[1].kind == nkCurly:
  944. result = copyTree(check)
  945. if access.kind == nkDotExpr:
  946. var a = copyTree(access)
  947. a[1] = check[2]
  948. result[2] = a
  949. # 'access.kind != nkDotExpr' can happen for object constructors
  950. # which we don't check yet
  951. else:
  952. # it is some 'not'
  953. assert check.getMagic == mNot
  954. result = buildProperFieldCheck(access, check[1], o).neg(o)
  955. proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef; produceError: bool) =
  956. for i in 1..<n.len:
  957. let check = buildProperFieldCheck(n[0], n[i], m.g.operators)
  958. if check != nil and m.doesImply(check) != impYes:
  959. if produceError:
  960. localError(conf, n.info, "field access outside of valid case branch: " & renderTree(n[0]))
  961. else:
  962. message(conf, n.info, warnProveField, renderTree(n[0]))
  963. break