guards.nim 35 KB

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