guards.nim 34 KB

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