guards.nim 34 KB

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