sempass2.nim 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361
  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. import
  10. intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
  11. wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
  12. modulegraphs, varpartitions, typeallowed
  13. when defined(useDfa):
  14. import dfa
  15. import liftdestructors
  16. include sinkparameter_inference
  17. #[ Second semantic checking pass over the AST. Necessary because the old
  18. way had some inherent problems. Performs:
  19. * effect+exception tracking
  20. * "usage before definition" checking
  21. * also now calls the "lift destructor logic" at strategic positions, this
  22. is about to be put into the spec:
  23. We treat assignment and sinks and destruction as identical.
  24. In the construct let/var x = expr() x's type is marked.
  25. In x = y the type of x is marked.
  26. For every sink parameter of type T T is marked.
  27. For every call f() the return type of f() is marked.
  28. ]#
  29. # ------------------------ exception and tag tracking -------------------------
  30. discard """
  31. exception tracking:
  32. a() # raises 'x', 'e'
  33. try:
  34. b() # raises 'e'
  35. except e:
  36. # must not undo 'e' here; hrm
  37. c()
  38. --> we need a stack of scopes for this analysis
  39. # XXX enhance the algorithm to care about 'dirty' expressions:
  40. lock a[i].L:
  41. inc i # mark 'i' dirty
  42. lock a[j].L:
  43. access a[i], a[j] # --> reject a[i]
  44. """
  45. type
  46. TEffects = object
  47. exc: PNode # stack of exceptions
  48. tags: PNode # list of tags
  49. bottom, inTryStmt, inExceptOrFinallyStmt, leftPartOfAsgn: int
  50. owner: PSym
  51. ownerModule: PSym
  52. init: seq[int] # list of initialized variables
  53. guards: TModel # nested guards
  54. locked: seq[PNode] # locked locations
  55. gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
  56. hasDangerousAssign: bool
  57. inEnforcedNoSideEffects: bool
  58. maxLockLevel, currLockLevel: TLockLevel
  59. currOptions: TOptions
  60. config: ConfigRef
  61. graph: ModuleGraph
  62. c: PContext
  63. PEffects = var TEffects
  64. proc `<`(a, b: TLockLevel): bool {.borrow.}
  65. proc `<=`(a, b: TLockLevel): bool {.borrow.}
  66. proc `==`(a, b: TLockLevel): bool {.borrow.}
  67. proc max(a, b: TLockLevel): TLockLevel {.borrow.}
  68. proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
  69. if typ == nil: return
  70. when false:
  71. let realType = typ.skipTypes(abstractInst)
  72. if realType.kind == tyRef and
  73. optSeqDestructors in tracked.config.globalOptions:
  74. createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
  75. createTypeBoundOps(tracked.graph, tracked.c, typ, info)
  76. if (tfHasAsgn in typ.flags) or
  77. optSeqDestructors in tracked.config.globalOptions:
  78. tracked.owner.flags.incl sfInjectDestructors
  79. proc isLocalVar(a: PEffects, s: PSym): bool =
  80. # and (s.kind != skParam or s.typ.kind == tyOut)
  81. s.kind in {skVar, skResult} and sfGlobal notin s.flags and
  82. s.owner == a.owner and s.typ != nil
  83. proc getLockLevel(t: PType): TLockLevel =
  84. var t = t
  85. # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
  86. if t.kind == tyGenericInst and t.len == 3: t = t[1]
  87. if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
  88. result = t.n.intVal.TLockLevel
  89. proc lockLocations(a: PEffects; pragma: PNode) =
  90. if pragma.kind != nkExprColonExpr:
  91. localError(a.config, pragma.info, "locks pragma without argument")
  92. return
  93. var firstLL = TLockLevel(-1'i16)
  94. for x in pragma[1]:
  95. let thisLL = getLockLevel(x.typ)
  96. if thisLL != 0.TLockLevel:
  97. if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
  98. localError(a.config, x.info, "invalid lock level: " & $thisLL)
  99. elif firstLL < 0.TLockLevel: firstLL = thisLL
  100. elif firstLL != thisLL:
  101. localError(a.config, x.info,
  102. "multi-lock requires the same static lock level for every operand")
  103. a.maxLockLevel = max(a.maxLockLevel, firstLL)
  104. a.locked.add x
  105. if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
  106. if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
  107. localError(a.config, pragma.info, "invalid nested locking")
  108. a.currLockLevel = firstLL
  109. proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
  110. # check whether the corresponding lock is held:
  111. for L in a.locked:
  112. if L.kind == nkSym and L.sym == guard: return
  113. # we allow accesses nevertheless in top level statements for
  114. # easier initialization:
  115. #if a.isTopLevel:
  116. # message(n.info, warnUnguardedAccess, renderTree(n))
  117. #else:
  118. if not a.isTopLevel:
  119. localError(a.config, n.info, "unguarded access: " & renderTree(n))
  120. # 'guard*' are checks which are concerned with 'guard' annotations
  121. # (var x{.guard: y.}: int)
  122. proc guardDotAccess(a: PEffects; n: PNode) =
  123. let ri = n[1]
  124. if ri.kind != nkSym or ri.sym.kind != skField: return
  125. var g = ri.sym.guard
  126. if g.isNil or a.isTopLevel: return
  127. # fixup guard:
  128. if g.kind == skUnknown:
  129. var field: PSym = nil
  130. var ty = n[0].typ.skipTypes(abstractPtrs)
  131. if ty.kind == tyTuple and not ty.n.isNil:
  132. field = lookupInRecord(ty.n, g.name)
  133. else:
  134. while ty != nil and ty.kind == tyObject:
  135. field = lookupInRecord(ty.n, g.name)
  136. if field != nil: break
  137. ty = ty[0]
  138. if ty == nil: break
  139. ty = ty.skipTypes(skipPtrs)
  140. if field == nil:
  141. localError(a.config, n.info, "invalid guard field: " & g.name.s)
  142. return
  143. g = field
  144. #ri.sym.guard = field
  145. # XXX unfortunately this is not correct for generic instantiations!
  146. if g.kind == skField:
  147. let dot = newNodeI(nkDotExpr, n.info, 2)
  148. dot[0] = n[0]
  149. dot[1] = newSymNode(g)
  150. dot.typ = g.typ
  151. for L in a.locked:
  152. #if a.guards.sameSubexprs(dot, L): return
  153. if guards.sameTree(dot, L): return
  154. localError(a.config, n.info, "unguarded access: " & renderTree(n))
  155. else:
  156. guardGlobal(a, n, g)
  157. proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
  158. if a.inTryStmt > 0 and a.config.exc == excSetjmp:
  159. incl(s.flags, sfVolatile)
  160. proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
  161. if n.kind != nkSym: return
  162. let s = n.sym
  163. if isLocalVar(a, s):
  164. if volatileCheck: makeVolatile(a, s)
  165. for x in a.init:
  166. if x == s.id: return
  167. a.init.add s.id
  168. proc initVarViaNew(a: PEffects, n: PNode) =
  169. if n.kind != nkSym: return
  170. let s = n.sym
  171. if {tfRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
  172. # 'x' is not nil, but that doesn't mean its "not nil" children
  173. # are initialized:
  174. initVar(a, n, volatileCheck=true)
  175. elif isLocalVar(a, s):
  176. makeVolatile(a, s)
  177. proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
  178. #assert false
  179. message(conf, n.info, warnGcUnsafe, renderTree(n))
  180. proc markGcUnsafe(a: PEffects; reason: PSym) =
  181. if not a.inEnforcedGcSafe:
  182. a.gcUnsafe = true
  183. if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
  184. proc markGcUnsafe(a: PEffects; reason: PNode) =
  185. if not a.inEnforcedGcSafe:
  186. a.gcUnsafe = true
  187. if a.owner.kind in routineKinds:
  188. if reason.kind == nkSym:
  189. a.owner.gcUnsafetyReason = reason.sym
  190. else:
  191. a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name,
  192. a.owner, reason.info, {})
  193. when true:
  194. template markSideEffect(a: PEffects; reason: typed) =
  195. if not a.inEnforcedNoSideEffects: a.hasSideEffect = true
  196. else:
  197. template markSideEffect(a: PEffects; reason: typed) =
  198. if not a.inEnforcedNoSideEffects: a.hasSideEffect = true
  199. markGcUnsafe(a, reason)
  200. proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
  201. let u = s.gcUnsafetyReason
  202. if u != nil and not cycleCheck.containsOrIncl(u.id):
  203. let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
  204. case u.kind
  205. of skLet, skVar:
  206. message(conf, s.info, msgKind,
  207. ("'$#' is not GC-safe as it accesses '$#'" &
  208. " which is a global using GC'ed memory") % [s.name.s, u.name.s])
  209. of routineKinds:
  210. # recursive call *always* produces only a warning so the full error
  211. # message is printed:
  212. listGcUnsafety(u, true, cycleCheck, conf)
  213. message(conf, s.info, msgKind,
  214. "'$#' is not GC-safe as it calls '$#'" %
  215. [s.name.s, u.name.s])
  216. of skParam, skForVar:
  217. message(conf, s.info, msgKind,
  218. "'$#' is not GC-safe as it performs an indirect call via '$#'" %
  219. [s.name.s, u.name.s])
  220. else:
  221. message(conf, u.info, msgKind,
  222. "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
  223. proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
  224. var cycleCheck = initIntSet()
  225. listGcUnsafety(s, onlyWarning, cycleCheck, conf)
  226. proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) =
  227. if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
  228. s.magic != mNimvm:
  229. if s.guard != nil: guardGlobal(a, n, s.guard)
  230. if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
  231. (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
  232. #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n)
  233. markGcUnsafe(a, s)
  234. markSideEffect(a, s)
  235. else:
  236. markSideEffect(a, s)
  237. proc useVar(a: PEffects, n: PNode) =
  238. let s = n.sym
  239. if a.inExceptOrFinallyStmt > 0:
  240. incl s.flags, sfUsedInFinallyOrExcept
  241. if isLocalVar(a, s):
  242. if sfNoInit in s.flags:
  243. # If the variable is explicitly marked as .noinit. do not emit any error
  244. a.init.add s.id
  245. elif s.id notin a.init:
  246. if s.typ.requiresInit:
  247. message(a.config, n.info, warnProveInit, s.name.s)
  248. elif a.leftPartOfAsgn <= 0:
  249. message(a.config, n.info, warnUninit, s.name.s)
  250. # prevent superfluous warnings about the same variable:
  251. a.init.add s.id
  252. useVarNoInitCheck(a, n, s)
  253. type
  254. TIntersection = seq[tuple[id, count: int]] # a simple count table
  255. proc addToIntersection(inter: var TIntersection, s: int) =
  256. for j in 0..<inter.len:
  257. if s == inter[j].id:
  258. inc inter[j].count
  259. return
  260. inter.add((id: s, count: 1))
  261. proc throws(tracked, n, orig: PNode) =
  262. if n.typ == nil or n.typ.kind != tyError:
  263. if orig != nil:
  264. let x = copyNode(n)
  265. x.info = orig.info
  266. tracked.add x
  267. else:
  268. tracked.add n
  269. proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
  270. result = g.sysTypeFromName(info, "Exception")
  271. proc excType(g: ModuleGraph; n: PNode): PType =
  272. # reraise is like raising E_Base:
  273. let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
  274. result = skipTypes(t, skipPtrs)
  275. proc createRaise(g: ModuleGraph; n: PNode): PNode =
  276. result = newNode(nkType)
  277. result.typ = getEbase(g, n.info)
  278. if not n.isNil: result.info = n.info
  279. proc createTag(g: ModuleGraph; n: PNode): PNode =
  280. result = newNode(nkType)
  281. result.typ = g.sysTypeFromName(n.info, "RootEffect")
  282. if not n.isNil: result.info = n.info
  283. proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
  284. assert e.kind != nkRaiseStmt
  285. var aa = a.exc
  286. for i in a.bottom..<aa.len:
  287. # we only track the first node that can have the effect E in order
  288. # to safe space and time.
  289. if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): return
  290. if e.typ != nil:
  291. if optNimV1Emulation in a.config.globalOptions or not isDefectException(e.typ):
  292. throws(a.exc, e, comesFrom)
  293. proc addTag(a: PEffects, e, comesFrom: PNode) =
  294. var aa = a.tags
  295. for i in 0..<aa.len:
  296. # we only track the first node that can have the effect E in order
  297. # to safe space and time.
  298. if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)): return
  299. throws(a.tags, e, comesFrom)
  300. proc mergeRaises(a: PEffects, b, comesFrom: PNode) =
  301. if b.isNil:
  302. addRaiseEffect(a, createRaise(a.graph, comesFrom), comesFrom)
  303. else:
  304. for effect in items(b): addRaiseEffect(a, effect, comesFrom)
  305. proc mergeTags(a: PEffects, b, comesFrom: PNode) =
  306. if b.isNil:
  307. addTag(a, createTag(a.graph, comesFrom), comesFrom)
  308. else:
  309. for effect in items(b): addTag(a, effect, comesFrom)
  310. proc listEffects(a: PEffects) =
  311. for e in items(a.exc): message(a.config, e.info, hintUser, typeToString(e.typ))
  312. for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
  313. #if a.maxLockLevel != 0:
  314. # message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
  315. proc catches(tracked: PEffects, e: PType) =
  316. let e = skipTypes(e, skipPtrs)
  317. var L = tracked.exc.len
  318. var i = tracked.bottom
  319. while i < L:
  320. # r supertype of e?
  321. if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
  322. tracked.exc[i] = tracked.exc[L-1]
  323. dec L
  324. else:
  325. inc i
  326. if tracked.exc.len > 0:
  327. setLen(tracked.exc.sons, L)
  328. else:
  329. assert L == 0
  330. proc catchesAll(tracked: PEffects) =
  331. if tracked.exc.len > 0:
  332. setLen(tracked.exc.sons, tracked.bottom)
  333. proc track(tracked: PEffects, n: PNode)
  334. proc trackTryStmt(tracked: PEffects, n: PNode) =
  335. let oldBottom = tracked.bottom
  336. tracked.bottom = tracked.exc.len
  337. let oldState = tracked.init.len
  338. var inter: TIntersection = @[]
  339. inc tracked.inTryStmt
  340. track(tracked, n[0])
  341. dec tracked.inTryStmt
  342. for i in oldState..<tracked.init.len:
  343. addToIntersection(inter, tracked.init[i])
  344. var branches = 1
  345. var hasFinally = false
  346. inc tracked.inExceptOrFinallyStmt
  347. # Collect the exceptions caught by the except branches
  348. for i in 1..<n.len:
  349. let b = n[i]
  350. if b.kind == nkExceptBranch:
  351. inc branches
  352. if b.len == 1:
  353. catchesAll(tracked)
  354. else:
  355. for j in 0..<b.len - 1:
  356. if b[j].isInfixAs():
  357. assert(b[j][1].kind == nkType)
  358. catches(tracked, b[j][1].typ)
  359. createTypeBoundOps(tracked, b[j][2].typ, b[j][2].info)
  360. else:
  361. assert(b[j].kind == nkType)
  362. catches(tracked, b[j].typ)
  363. else:
  364. assert b.kind == nkFinally
  365. # Add any other exception raised in the except bodies
  366. for i in 1..<n.len:
  367. let b = n[i]
  368. if b.kind == nkExceptBranch:
  369. setLen(tracked.init, oldState)
  370. track(tracked, b[^1])
  371. for i in oldState..<tracked.init.len:
  372. addToIntersection(inter, tracked.init[i])
  373. else:
  374. setLen(tracked.init, oldState)
  375. track(tracked, b[^1])
  376. hasFinally = true
  377. tracked.bottom = oldBottom
  378. dec tracked.inExceptOrFinallyStmt
  379. if not hasFinally:
  380. setLen(tracked.init, oldState)
  381. for id, count in items(inter):
  382. if count == branches: tracked.init.add id
  383. proc isIndirectCall(n: PNode, owner: PSym): bool =
  384. # we don't count f(...) as an indirect call if 'f' is an parameter.
  385. # Instead we track expressions of type tyProc too. See the manual for
  386. # details:
  387. if n.kind != nkSym:
  388. result = true
  389. elif n.sym.kind == skParam:
  390. result = owner != n.sym.owner or owner == nil
  391. elif n.sym.kind notin routineKinds:
  392. result = true
  393. proc isForwardedProc(n: PNode): bool =
  394. result = n.kind == nkSym and sfForward in n.sym.flags
  395. proc trackPragmaStmt(tracked: PEffects, n: PNode) =
  396. for i in 0..<n.len:
  397. var it = n[i]
  398. let pragma = whichPragma(it)
  399. if pragma == wEffects:
  400. # list the computed effects up to here:
  401. listEffects(tracked)
  402. template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {}
  403. proc importedFromC(n: PNode): bool =
  404. # when imported from C, we assume GC-safety.
  405. result = n.kind == nkSym and sfImportc in n.sym.flags
  406. proc getLockLevel(s: PSym): TLockLevel =
  407. result = s.typ.lockLevel
  408. if result == UnspecifiedLockLevel:
  409. if {sfImportc, sfNoSideEffect} * s.flags != {} or
  410. tfNoSideEffect in s.typ.flags:
  411. result = 0.TLockLevel
  412. else:
  413. result = UnknownLockLevel
  414. #message(s.info, warnUser, "FOR THIS " & s.name.s)
  415. proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
  416. if lockLevel >= tracked.currLockLevel:
  417. # if in lock section:
  418. if tracked.currLockLevel > 0.TLockLevel:
  419. localError tracked.config, n.info, errGenerated,
  420. "expected lock level < " & $tracked.currLockLevel &
  421. " but got lock level " & $lockLevel
  422. tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
  423. proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
  424. let pragma = s.ast[pragmasPos]
  425. let spec = effectSpec(pragma, wRaises)
  426. mergeRaises(tracked, spec, n)
  427. let tagSpec = effectSpec(pragma, wTags)
  428. mergeTags(tracked, tagSpec, n)
  429. if notGcSafe(s.typ) and sfImportc notin s.flags:
  430. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  431. markGcUnsafe(tracked, s)
  432. if tfNoSideEffect notin s.typ.flags:
  433. markSideEffect(tracked, s)
  434. mergeLockLevels(tracked, n, s.getLockLevel)
  435. proc procVarCheck(n: PNode; conf: ConfigRef) =
  436. if n.kind in nkSymChoices:
  437. for x in n: procVarCheck(x, conf)
  438. elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
  439. localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s)
  440. proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
  441. let n = n.skipConv
  442. if paramType.isNil or paramType.kind != tyTypeDesc:
  443. procVarCheck skipConvAndClosure(n), tracked.config
  444. #elif n.kind in nkSymChoices:
  445. # echo "came here"
  446. let paramType = paramType.skipTypesOrNil(abstractInst)
  447. if paramType != nil and tfNotNil in paramType.flags and n.typ != nil:
  448. let ntyp = n.typ.skipTypesOrNil({tyVar, tyLent, tySink})
  449. if ntyp != nil and tfNotNil notin ntyp.flags:
  450. if isAddrNode(n):
  451. # addr(x[]) can't be proven, but addr(x) can:
  452. if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
  453. elif (n.kind == nkSym and n.sym.kind in routineKinds) or
  454. (n.kind in procDefs+{nkObjConstr, nkBracket, nkClosure, nkStrLit..nkTripleStrLit}) or
  455. (n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mArrToSeq) or
  456. n.typ.kind == tyTypeDesc:
  457. # 'p' is not nil obviously:
  458. return
  459. case impliesNotNil(tracked.guards, n)
  460. of impUnknown:
  461. message(tracked.config, n.info, errGenerated,
  462. "cannot prove '$1' is not nil" % n.renderTree)
  463. of impNo:
  464. message(tracked.config, n.info, errGenerated,
  465. "'$1' is provably nil" % n.renderTree)
  466. of impYes: discard
  467. proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
  468. addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
  469. addTag(tracked, createTag(tracked.graph, n), nil)
  470. let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
  471. else: op.lockLevel
  472. #if lockLevel == UnknownLockLevel:
  473. # message(n.info, warnUser, "had to assume the worst here")
  474. mergeLockLevels(tracked, n, lockLevel)
  475. proc isOwnedProcVar(n: PNode; owner: PSym): bool =
  476. # XXX prove the soundness of this effect system rule
  477. result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner
  478. proc isNoEffectList(n: PNode): bool {.inline.} =
  479. assert n.kind == nkEffectList
  480. n.len == 0 or (n[tagEffects] == nil and n[exceptionEffects] == nil)
  481. proc isTrival(caller: PNode): bool {.inline.} =
  482. result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved, mSwap}
  483. proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) =
  484. let a = skipConvAndClosure(n)
  485. let op = a.typ
  486. # assume indirect calls are taken here:
  487. if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and not isTrival(caller):
  488. internalAssert tracked.config, op.n[0].kind == nkEffectList
  489. var effectList = op.n[0]
  490. var s = n.skipConv
  491. if s.kind == nkCast and s[1].typ.kind == tyProc:
  492. s = s[1]
  493. if s.kind == nkSym and s.sym.kind in routineKinds and isNoEffectList(effectList):
  494. propagateEffects(tracked, n, s.sym)
  495. elif isNoEffectList(effectList):
  496. if isForwardedProc(n):
  497. # we have no explicit effects but it's a forward declaration and so it's
  498. # stated there are no additional effects, so simply propagate them:
  499. propagateEffects(tracked, n, n.sym)
  500. elif not isOwnedProcVar(a, tracked.owner):
  501. # we have no explicit effects so assume the worst:
  502. assumeTheWorst(tracked, n, op)
  503. # assume GcUnsafe unless in its type; 'forward' does not matter:
  504. if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
  505. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  506. markGcUnsafe(tracked, a)
  507. elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
  508. markSideEffect(tracked, a)
  509. else:
  510. mergeRaises(tracked, effectList[exceptionEffects], n)
  511. mergeTags(tracked, effectList[tagEffects], n)
  512. if notGcSafe(op):
  513. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  514. markGcUnsafe(tracked, a)
  515. elif tfNoSideEffect notin op.flags:
  516. markSideEffect(tracked, a)
  517. if paramType != nil and paramType.kind in {tyVar}:
  518. invalidateFacts(tracked.guards, n)
  519. if n.kind == nkSym and isLocalVar(tracked, n.sym):
  520. makeVolatile(tracked, n.sym)
  521. if paramType != nil and paramType.kind == tyProc and tfGcSafe in paramType.flags:
  522. let argtype = skipTypes(a.typ, abstractInst)
  523. # XXX figure out why this can be a non tyProc here. See httpclient.nim for an
  524. # example that triggers it.
  525. if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
  526. localError(tracked.config, n.info, $n & " is not GC safe")
  527. notNilCheck(tracked, n, paramType)
  528. proc breaksBlock(n: PNode): bool =
  529. # semantic check doesn't allow statements after raise, break, return or
  530. # call to noreturn proc, so it is safe to check just the last statements
  531. var it = n
  532. while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
  533. it = it.lastSon
  534. result = it.kind in {nkBreakStmt, nkReturnStmt, nkRaiseStmt} or
  535. it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
  536. proc trackCase(tracked: PEffects, n: PNode) =
  537. track(tracked, n[0])
  538. let oldState = tracked.init.len
  539. let oldFacts = tracked.guards.s.len
  540. let stringCase = n[0].typ != nil and skipTypes(n[0].typ,
  541. abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
  542. let interesting = not stringCase and interestingCaseExpr(n[0]) and
  543. tracked.config.hasWarn(warnProveField)
  544. var inter: TIntersection = @[]
  545. var toCover = 0
  546. for i in 1..<n.len:
  547. let branch = n[i]
  548. setLen(tracked.init, oldState)
  549. if interesting:
  550. setLen(tracked.guards.s, oldFacts)
  551. addCaseBranchFacts(tracked.guards, n, i)
  552. for i in 0..<branch.len:
  553. track(tracked, branch[i])
  554. if not breaksBlock(branch.lastSon): inc toCover
  555. for i in oldState..<tracked.init.len:
  556. addToIntersection(inter, tracked.init[i])
  557. setLen(tracked.init, oldState)
  558. if not stringCase or lastSon(n).kind == nkElse:
  559. for id, count in items(inter):
  560. if count >= toCover: tracked.init.add id
  561. # else we can't merge
  562. setLen(tracked.guards.s, oldFacts)
  563. proc trackIf(tracked: PEffects, n: PNode) =
  564. track(tracked, n[0][0])
  565. let oldFacts = tracked.guards.s.len
  566. addFact(tracked.guards, n[0][0])
  567. let oldState = tracked.init.len
  568. var inter: TIntersection = @[]
  569. var toCover = 0
  570. track(tracked, n[0][1])
  571. if not breaksBlock(n[0][1]): inc toCover
  572. for i in oldState..<tracked.init.len:
  573. addToIntersection(inter, tracked.init[i])
  574. for i in 1..<n.len:
  575. let branch = n[i]
  576. setLen(tracked.guards.s, oldFacts)
  577. for j in 0..i-1:
  578. addFactNeg(tracked.guards, n[j][0])
  579. if branch.len > 1:
  580. addFact(tracked.guards, branch[0])
  581. setLen(tracked.init, oldState)
  582. for i in 0..<branch.len:
  583. track(tracked, branch[i])
  584. if not breaksBlock(branch.lastSon): inc toCover
  585. for i in oldState..<tracked.init.len:
  586. addToIntersection(inter, tracked.init[i])
  587. setLen(tracked.init, oldState)
  588. if lastSon(n).len == 1:
  589. for id, count in items(inter):
  590. if count >= toCover: tracked.init.add id
  591. # else we can't merge as it is not exhaustive
  592. setLen(tracked.guards.s, oldFacts)
  593. proc trackBlock(tracked: PEffects, n: PNode) =
  594. if n.kind in {nkStmtList, nkStmtListExpr}:
  595. var oldState = -1
  596. for i in 0..<n.len:
  597. if hasSubnodeWith(n[i], nkBreakStmt):
  598. # block:
  599. # x = def
  600. # if ...: ... break # some nested break
  601. # y = def
  602. # --> 'y' not defined after block!
  603. if oldState < 0: oldState = tracked.init.len
  604. track(tracked, n[i])
  605. if oldState > 0: setLen(tracked.init, oldState)
  606. else:
  607. track(tracked, n)
  608. proc paramType(op: PType, i: int): PType =
  609. if op != nil and i < op.len: result = op[i]
  610. proc cstringCheck(tracked: PEffects; n: PNode) =
  611. if n[0].typ.kind == tyCString and (let a = skipConv(n[1]);
  612. a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
  613. message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
  614. proc patchResult(c: PEffects; n: PNode) =
  615. if n.kind == nkSym and n.sym.kind == skResult:
  616. let fn = c.owner
  617. if fn != nil and fn.kind in routineKinds and fn.ast != nil and resultPos < fn.ast.len:
  618. n.sym = fn.ast[resultPos].sym
  619. else:
  620. localError(c.config, n.info, "routine has no return type, but .requires contains 'result'")
  621. else:
  622. for i in 0..<safeLen(n):
  623. patchResult(c, n[i])
  624. proc checkLe(c: PEffects; a, b: PNode) =
  625. case proveLe(c.guards, a, b)
  626. of impUnknown:
  627. #for g in c.guards.s:
  628. # if g != nil: echo "I Know ", g
  629. message(c.config, a.info, warnStaticIndexCheck,
  630. "cannot prove: " & $a & " <= " & $b)
  631. of impYes:
  632. discard
  633. of impNo:
  634. message(c.config, a.info, warnStaticIndexCheck,
  635. "can prove: " & $a & " > " & $b)
  636. proc checkBounds(c: PEffects; arr, idx: PNode) =
  637. checkLe(c, lowBound(c.config, arr), idx)
  638. checkLe(c, idx, highBound(c.config, arr, c.guards.o))
  639. proc checkRange(c: PEffects; value: PNode; typ: PType) =
  640. let t = typ.skipTypes(abstractInst - {tyRange})
  641. if t.kind == tyRange:
  642. let lowBound = copyTree(t.n[0])
  643. lowBound.info = value.info
  644. let highBound = copyTree(t.n[1])
  645. highBound.info = value.info
  646. checkLe(c, lowBound, value)
  647. checkLe(c, value, highBound)
  648. proc trackCall(tracked: PEffects; n: PNode) =
  649. template gcsafeAndSideeffectCheck() =
  650. if notGcSafe(op) and not importedFromC(a):
  651. # and it's not a recursive call:
  652. if not (a.kind == nkSym and a.sym == tracked.owner):
  653. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  654. markGcUnsafe(tracked, a)
  655. if tfNoSideEffect notin op.flags and not importedFromC(a):
  656. # and it's not a recursive call:
  657. if not (a.kind == nkSym and a.sym == tracked.owner):
  658. markSideEffect(tracked, a)
  659. # p's effects are ours too:
  660. var a = n[0]
  661. #if canRaise(a):
  662. # echo "this can raise ", tracked.config $ n.info
  663. let op = a.typ
  664. if n.typ != nil:
  665. if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  666. createTypeBoundOps(tracked, n.typ, n.info)
  667. if getConstExpr(tracked.ownerModule, n, tracked.graph) != nil:
  668. return
  669. if a.kind == nkCast and a[1].typ.kind == tyProc:
  670. a = a[1]
  671. # XXX: in rare situations, templates and macros will reach here after
  672. # calling getAst(templateOrMacro()). Currently, templates and macros
  673. # are indistinguishable from normal procs (both have tyProc type) and
  674. # we can detect them only by checking for attached nkEffectList.
  675. if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList:
  676. if a.kind == nkSym:
  677. if a.sym == tracked.owner: tracked.isRecursive = true
  678. # even for recursive calls we need to check the lock levels (!):
  679. mergeLockLevels(tracked, n, a.sym.getLockLevel)
  680. if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
  681. else:
  682. mergeLockLevels(tracked, n, op.lockLevel)
  683. var effectList = op.n[0]
  684. if a.kind == nkSym and a.sym.kind == skMethod:
  685. propagateEffects(tracked, n, a.sym)
  686. elif isNoEffectList(effectList):
  687. if isForwardedProc(a):
  688. propagateEffects(tracked, n, a.sym)
  689. elif isIndirectCall(a, tracked.owner):
  690. assumeTheWorst(tracked, n, op)
  691. gcsafeAndSideeffectCheck()
  692. else:
  693. mergeRaises(tracked, effectList[exceptionEffects], n)
  694. mergeTags(tracked, effectList[tagEffects], n)
  695. gcsafeAndSideeffectCheck()
  696. if a.kind != nkSym or a.sym.magic != mNBindSym:
  697. for i in 1..<n.len: trackOperandForIndirectCall(tracked, n[i], paramType(op, i), a)
  698. if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
  699. # may not look like an assignment, but it is:
  700. let arg = n[1]
  701. initVarViaNew(tracked, arg)
  702. if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}:
  703. if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
  704. n[2].intVal == 0:
  705. # var s: seq[notnil]; newSeq(s, 0) is a special case!
  706. discard
  707. else:
  708. message(tracked.config, arg.info, warnProveInit, $arg)
  709. # check required for 'nim check':
  710. if n[1].typ.len > 0:
  711. createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
  712. createTypeBoundOps(tracked, n[1].typ, n.info)
  713. # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
  714. elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and
  715. optStaticBoundsCheck in tracked.currOptions:
  716. checkBounds(tracked, n[1], n[2])
  717. if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
  718. tracked.owner.kind != skMacro:
  719. var opKind = find(AttachedOpToStr, a.sym.name.s.normalize)
  720. if a.sym.name.s.normalize == "=": opKind = attachedAsgn.int
  721. if opKind != -1:
  722. # rebind type bounds operations after createTypeBoundOps call
  723. let t = n[1].typ.skipTypes({tyAlias, tyVar})
  724. if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]:
  725. createTypeBoundOps(tracked, t, n.info)
  726. let op = t.attachedOps[TTypeAttachedOp(opKind)]
  727. if op != nil:
  728. n[0].sym = op
  729. if a.kind != nkSym or a.sym.magic != mRunnableExamples:
  730. for i in 0..<n.safeLen:
  731. track(tracked, n[i])
  732. if op != nil and op.kind == tyProc:
  733. for i in 1..<min(n.safeLen, op.len):
  734. case op[i].kind
  735. of tySink:
  736. createTypeBoundOps(tracked, op[i][0], n.info)
  737. checkForSink(tracked.config, tracked.owner, n[i])
  738. of tyVar:
  739. tracked.hasDangerousAssign = true
  740. #of tyOut:
  741. # consider this case: p(out x, x); we want to remark that 'x' is not
  742. # initialized until after the call. Since we do this after we analysed the
  743. # call, this is fine.
  744. # initVar(tracked, n[i].skipAddr, false)
  745. else: discard
  746. type
  747. PragmaBlockContext = object
  748. oldLocked: int
  749. oldLockLevel: TLockLevel
  750. enforcedGcSafety, enforceNoSideEffects: bool
  751. oldExc, oldTags: int
  752. exc, tags: PNode
  753. proc createBlockContext(tracked: PEffects): PragmaBlockContext =
  754. result = PragmaBlockContext(oldLocked: tracked.locked.len,
  755. oldLockLevel: tracked.currLockLevel,
  756. enforcedGcSafety: false, enforceNoSideEffects: false,
  757. oldExc: tracked.exc.len, oldTags: tracked.tags.len)
  758. proc applyBlockContext(tracked: PEffects, bc: PragmaBlockContext) =
  759. if bc.enforcedGcSafety: tracked.inEnforcedGcSafe = true
  760. if bc.enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true
  761. proc unapplyBlockContext(tracked: PEffects; bc: PragmaBlockContext) =
  762. if bc.enforcedGcSafety: tracked.inEnforcedGcSafe = false
  763. if bc.enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false
  764. setLen(tracked.locked, bc.oldLocked)
  765. tracked.currLockLevel = bc.oldLockLevel
  766. if bc.exc != nil:
  767. # beware that 'raises: []' is very different from not saying
  768. # anything about 'raises' in the 'cast' at all. Same applies for 'tags'.
  769. setLen(tracked.exc.sons, bc.oldExc)
  770. for e in bc.exc:
  771. addRaiseEffect(tracked, e, e)
  772. if bc.tags != nil:
  773. setLen(tracked.tags.sons, bc.oldTags)
  774. for t in bc.tags:
  775. addTag(tracked, t, t)
  776. proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
  777. case whichPragma(pragma)
  778. of wGcSafe:
  779. bc.enforcedGcSafety = true
  780. of wNoSideEffect:
  781. bc.enforceNoSideEffects = true
  782. of wTags:
  783. let n = pragma[1]
  784. if n.kind in {nkCurly, nkBracket}:
  785. bc.tags = n
  786. else:
  787. bc.tags = newNodeI(nkArgList, pragma.info)
  788. bc.tags.add n
  789. of wRaises:
  790. let n = pragma[1]
  791. if n.kind in {nkCurly, nkBracket}:
  792. bc.exc = n
  793. else:
  794. bc.exc = newNodeI(nkArgList, pragma.info)
  795. bc.exc.add n
  796. else:
  797. localError(tracked.config, pragma.info,
  798. "invalid pragma block: " & $pragma)
  799. proc track(tracked: PEffects, n: PNode) =
  800. case n.kind
  801. of nkSym:
  802. useVar(tracked, n)
  803. if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
  804. tracked.owner.flags.incl sfInjectDestructors
  805. # bug #15038: ensure consistency
  806. if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
  807. of nkHiddenAddr, nkAddr:
  808. if n[0].kind == nkSym and isLocalVar(tracked, n[0].sym):
  809. useVarNoInitCheck(tracked, n[0], n[0].sym)
  810. else:
  811. track(tracked, n[0])
  812. of nkRaiseStmt:
  813. if n[0].kind != nkEmpty:
  814. n[0].info = n.info
  815. #throws(tracked.exc, n[0])
  816. addRaiseEffect(tracked, n[0], nil)
  817. for i in 0..<n.safeLen:
  818. track(tracked, n[i])
  819. createTypeBoundOps(tracked, n[0].typ, n.info)
  820. else:
  821. # A `raise` with no arguments means we're going to re-raise the exception
  822. # being handled or, if outside of an `except` block, a `ReraiseDefect`.
  823. # Here we add a `Exception` tag in order to cover both the cases.
  824. addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
  825. of nkCallKinds:
  826. trackCall(tracked, n)
  827. of nkDotExpr:
  828. guardDotAccess(tracked, n)
  829. for i in 0..<n.len: track(tracked, n[i])
  830. of nkCheckedFieldExpr:
  831. track(tracked, n[0])
  832. if tracked.config.hasWarn(warnProveField):
  833. checkFieldAccess(tracked.guards, n, tracked.config)
  834. of nkTryStmt: trackTryStmt(tracked, n)
  835. of nkPragma: trackPragmaStmt(tracked, n)
  836. of nkAsgn, nkFastAsgn:
  837. track(tracked, n[1])
  838. initVar(tracked, n[0], volatileCheck=true)
  839. invalidateFacts(tracked.guards, n[0])
  840. inc tracked.leftPartOfAsgn
  841. track(tracked, n[0])
  842. dec tracked.leftPartOfAsgn
  843. addAsgnFact(tracked.guards, n[0], n[1])
  844. notNilCheck(tracked, n[1], n[0].typ)
  845. when false: cstringCheck(tracked, n)
  846. if tracked.owner.kind != skMacro:
  847. createTypeBoundOps(tracked, n[0].typ, n.info)
  848. if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym):
  849. checkForSink(tracked.config, tracked.owner, n[1])
  850. if not tracked.hasDangerousAssign and n[0].kind != nkSym:
  851. tracked.hasDangerousAssign = true
  852. of nkVarSection, nkLetSection:
  853. for child in n:
  854. let last = lastSon(child)
  855. if last.kind != nkEmpty: track(tracked, last)
  856. if tracked.owner.kind != skMacro:
  857. if child.kind == nkVarTuple:
  858. createTypeBoundOps(tracked, child[^1].typ, child.info)
  859. for i in 0..<child.len-2:
  860. createTypeBoundOps(tracked, child[i].typ, child.info)
  861. else:
  862. createTypeBoundOps(tracked, child[0].typ, child.info)
  863. if child.kind == nkIdentDefs and last.kind != nkEmpty:
  864. for i in 0..<child.len-2:
  865. initVar(tracked, child[i], volatileCheck=false)
  866. addAsgnFact(tracked.guards, child[i], last)
  867. notNilCheck(tracked, last, child[i].typ)
  868. elif child.kind == nkVarTuple and last.kind != nkEmpty:
  869. for i in 0..<child.len-1:
  870. if child[i].kind == nkEmpty or
  871. child[i].kind == nkSym and child[i].sym.name.s == "_":
  872. continue
  873. initVar(tracked, child[i], volatileCheck=false)
  874. if last.kind in {nkPar, nkTupleConstr}:
  875. addAsgnFact(tracked.guards, child[i], last[i])
  876. notNilCheck(tracked, last[i], child[i].typ)
  877. # since 'var (a, b): T = ()' is not even allowed, there is always type
  878. # inference for (a, b) and thus no nil checking is necessary.
  879. of nkConstSection:
  880. for child in n:
  881. let last = lastSon(child)
  882. track(tracked, last)
  883. of nkCaseStmt: trackCase(tracked, n)
  884. of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
  885. of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
  886. of nkWhileStmt:
  887. # 'while true' loop?
  888. if isTrue(n[0]):
  889. trackBlock(tracked, n[1])
  890. else:
  891. # loop may never execute:
  892. let oldState = tracked.init.len
  893. let oldFacts = tracked.guards.s.len
  894. addFact(tracked.guards, n[0])
  895. track(tracked, n[0])
  896. track(tracked, n[1])
  897. setLen(tracked.init, oldState)
  898. setLen(tracked.guards.s, oldFacts)
  899. of nkForStmt, nkParForStmt:
  900. # we are very conservative here and assume the loop is never executed:
  901. let oldState = tracked.init.len
  902. let oldFacts = tracked.guards.s.len
  903. let iterCall = n[n.len-2]
  904. if optStaticBoundsCheck in tracked.currOptions and iterCall.kind in nkCallKinds:
  905. let op = iterCall[0]
  906. if op.kind == nkSym and fromSystem(op.sym):
  907. let iterVar = n[0]
  908. case op.sym.name.s
  909. of "..", "countup", "countdown":
  910. let lower = iterCall[1]
  911. let upper = iterCall[2]
  912. # for i in 0..n means 0 <= i and i <= n. Countdown is
  913. # the same since only the iteration direction changes.
  914. addFactLe(tracked.guards, lower, iterVar)
  915. addFactLe(tracked.guards, iterVar, upper)
  916. of "..<":
  917. let lower = iterCall[1]
  918. let upper = iterCall[2]
  919. addFactLe(tracked.guards, lower, iterVar)
  920. addFactLt(tracked.guards, iterVar, upper)
  921. else: discard
  922. for i in 0..<n.len-2:
  923. let it = n[i]
  924. track(tracked, it)
  925. if tracked.owner.kind != skMacro:
  926. if it.kind == nkVarTuple:
  927. for x in it:
  928. createTypeBoundOps(tracked, x.typ, x.info)
  929. else:
  930. createTypeBoundOps(tracked, it.typ, it.info)
  931. let loopBody = n[^1]
  932. if tracked.owner.kind != skMacro and iterCall.safeLen > 1:
  933. # XXX this is a bit hacky:
  934. if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}:
  935. createTypeBoundOps(tracked, iterCall[1].typ, iterCall[1].info)
  936. track(tracked, iterCall)
  937. track(tracked, loopBody)
  938. setLen(tracked.init, oldState)
  939. setLen(tracked.guards.s, oldFacts)
  940. of nkObjConstr:
  941. when false: track(tracked, n[0])
  942. let oldFacts = tracked.guards.s.len
  943. for i in 1..<n.len:
  944. let x = n[i]
  945. track(tracked, x)
  946. if x[0].kind == nkSym and sfDiscriminant in x[0].sym.flags:
  947. addDiscriminantFact(tracked.guards, x)
  948. if tracked.owner.kind != skMacro:
  949. createTypeBoundOps(tracked, x[1].typ, n.info)
  950. if x.kind == nkExprColonExpr:
  951. if x[0].kind == nkSym:
  952. notNilCheck(tracked, x[1], x[0].sym.typ)
  953. checkForSink(tracked.config, tracked.owner, x[1])
  954. else:
  955. checkForSink(tracked.config, tracked.owner, x)
  956. setLen(tracked.guards.s, oldFacts)
  957. if tracked.owner.kind != skMacro:
  958. # XXX n.typ can be nil in runnableExamples, we need to do something about it.
  959. if n.typ != nil and n.typ.skipTypes(abstractInst).kind == tyRef:
  960. createTypeBoundOps(tracked, n.typ.lastSon, n.info)
  961. createTypeBoundOps(tracked, n.typ, n.info)
  962. of nkTupleConstr:
  963. for i in 0..<n.len:
  964. track(tracked, n[i])
  965. if tracked.owner.kind != skMacro:
  966. if n[i].kind == nkExprColonExpr:
  967. createTypeBoundOps(tracked, n[i][0].typ, n.info)
  968. else:
  969. createTypeBoundOps(tracked, n[i].typ, n.info)
  970. checkForSink(tracked.config, tracked.owner, n[i])
  971. of nkPragmaBlock:
  972. let pragmaList = n[0]
  973. var bc = createBlockContext(tracked)
  974. for i in 0..<pragmaList.len:
  975. let pragma = whichPragma(pragmaList[i])
  976. case pragma
  977. of wLocks:
  978. lockLocations(tracked, pragmaList[i])
  979. of wGcSafe:
  980. bc.enforcedGcSafety = true
  981. of wNoSideEffect:
  982. bc.enforceNoSideEffects = true
  983. of wCast:
  984. castBlock(tracked, pragmaList[i][1], bc)
  985. else:
  986. discard
  987. applyBlockContext(tracked, bc)
  988. track(tracked, n.lastSon)
  989. unapplyBlockContext(tracked, bc)
  990. of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
  991. nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
  992. discard
  993. of nkCast:
  994. if n.len == 2:
  995. track(tracked, n[1])
  996. if tracked.owner.kind != skMacro:
  997. createTypeBoundOps(tracked, n.typ, n.info)
  998. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  999. if n.len == 2:
  1000. track(tracked, n[1])
  1001. if tracked.owner.kind != skMacro:
  1002. createTypeBoundOps(tracked, n.typ, n.info)
  1003. # This is a hacky solution in order to fix bug #13110. Hopefully
  1004. # a better solution will come up eventually.
  1005. if n[1].typ.kind != tyString:
  1006. createTypeBoundOps(tracked, n[1].typ, n[1].info)
  1007. if optStaticBoundsCheck in tracked.currOptions:
  1008. checkRange(tracked, n[1], n.typ)
  1009. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  1010. if n.len == 1:
  1011. track(tracked, n[0])
  1012. if tracked.owner.kind != skMacro:
  1013. createTypeBoundOps(tracked, n.typ, n.info)
  1014. createTypeBoundOps(tracked, n[0].typ, n[0].info)
  1015. if optStaticBoundsCheck in tracked.currOptions:
  1016. checkRange(tracked, n[0], n.typ)
  1017. of nkBracket:
  1018. for i in 0..<n.safeLen:
  1019. track(tracked, n[i])
  1020. checkForSink(tracked.config, tracked.owner, n[i])
  1021. if tracked.owner.kind != skMacro:
  1022. createTypeBoundOps(tracked, n.typ, n.info)
  1023. of nkBracketExpr:
  1024. if optStaticBoundsCheck in tracked.currOptions and n.len == 2:
  1025. if n[0].typ != nil and skipTypes(n[0].typ, abstractVar).kind != tyTuple:
  1026. checkBounds(tracked, n[0], n[1])
  1027. track(tracked, n[0])
  1028. dec tracked.leftPartOfAsgn
  1029. for i in 1 ..< n.len: track(tracked, n[i])
  1030. inc tracked.leftPartOfAsgn
  1031. else:
  1032. for i in 0..<n.safeLen: track(tracked, n[i])
  1033. proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
  1034. if spec.typ.kind == tyOr:
  1035. for t in spec.typ.sons:
  1036. if safeInheritanceDiff(g.excType(real), t) <= 0:
  1037. return true
  1038. else:
  1039. return safeInheritanceDiff(g.excType(real), spec.typ) <= 0
  1040. proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool;
  1041. effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.};
  1042. hintsArg: PNode = nil) =
  1043. # check that any real exception is listed in 'spec'; mark those as used;
  1044. # report any unused exception
  1045. var used = initIntSet()
  1046. for r in items(real):
  1047. block search:
  1048. for s in 0..<spec.len:
  1049. if effectPredicate(g, spec[s], r):
  1050. used.incl(s)
  1051. break search
  1052. # XXX call graph analysis would be nice here!
  1053. pushInfoContext(g.config, spec.info)
  1054. localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
  1055. popInfoContext(g.config)
  1056. # hint about unnecessarily listed exception types:
  1057. if hints:
  1058. for s in 0..<spec.len:
  1059. if not used.contains(s):
  1060. message(g.config, spec[s].info, hintXCannotRaiseY,
  1061. "'$1' cannot raise '$2'" % [renderTree(hintsArg), renderTree(spec[s])])
  1062. proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
  1063. ## checks for consistent effects for multi methods.
  1064. let actual = branch.typ.n[0]
  1065. if actual.len != effectListLen: return
  1066. let p = disp.ast[pragmasPos]
  1067. let raisesSpec = effectSpec(p, wRaises)
  1068. if not isNil(raisesSpec):
  1069. checkRaisesSpec(g, raisesSpec, actual[exceptionEffects],
  1070. "can raise an unlisted exception: ", hints=off, subtypeRelation)
  1071. let tagsSpec = effectSpec(p, wTags)
  1072. if not isNil(tagsSpec):
  1073. checkRaisesSpec(g, tagsSpec, actual[tagEffects],
  1074. "can have an unlisted effect: ", hints=off, subtypeRelation)
  1075. if sfThread in disp.flags and notGcSafe(branch.typ):
  1076. localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
  1077. branch.name.s)
  1078. when defined(drnim):
  1079. if not g.compatibleProps(g, disp.typ, branch.typ):
  1080. localError(g.config, branch.info, "for method '" & branch.name.s &
  1081. "' the `.requires` or `.ensures` properties are incompatible.")
  1082. if branch.typ.lockLevel > disp.typ.lockLevel:
  1083. when true:
  1084. message(g.config, branch.info, warnLockLevel,
  1085. "base method has lock level $1, but dispatcher has $2" %
  1086. [$branch.typ.lockLevel, $disp.typ.lockLevel])
  1087. else:
  1088. # XXX make this an error after bigbreak has been released:
  1089. localError(g.config, branch.info,
  1090. "base method has lock level $1, but dispatcher has $2" %
  1091. [$branch.typ.lockLevel, $disp.typ.lockLevel])
  1092. proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
  1093. var effects = t.n[0]
  1094. if t.kind != tyProc or effects.kind != nkEffectList: return
  1095. if n.kind != nkEmpty:
  1096. internalAssert g.config, effects.len == 0
  1097. newSeq(effects.sons, effectListLen)
  1098. let raisesSpec = effectSpec(n, wRaises)
  1099. if not isNil(raisesSpec):
  1100. effects[exceptionEffects] = raisesSpec
  1101. let tagsSpec = effectSpec(n, wTags)
  1102. if not isNil(tagsSpec):
  1103. effects[tagEffects] = tagsSpec
  1104. let requiresSpec = propSpec(n, wRequires)
  1105. if not isNil(requiresSpec):
  1106. effects[requiresEffects] = requiresSpec
  1107. let ensuresSpec = propSpec(n, wEnsures)
  1108. if not isNil(ensuresSpec):
  1109. effects[ensuresEffects] = ensuresSpec
  1110. effects[pragmasEffects] = n
  1111. proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) =
  1112. newSeq(effects.sons, effectListLen)
  1113. effects[exceptionEffects] = newNodeI(nkArgList, s.info)
  1114. effects[tagEffects] = newNodeI(nkArgList, s.info)
  1115. effects[requiresEffects] = g.emptyNode
  1116. effects[ensuresEffects] = g.emptyNode
  1117. effects[pragmasEffects] = g.emptyNode
  1118. t.exc = effects[exceptionEffects]
  1119. t.tags = effects[tagEffects]
  1120. t.owner = s
  1121. t.ownerModule = s.getModule
  1122. t.init = @[]
  1123. t.guards.s = @[]
  1124. t.guards.o = initOperators(g)
  1125. when defined(drnim):
  1126. t.currOptions = g.config.options + s.options - {optStaticBoundsCheck}
  1127. else:
  1128. t.currOptions = g.config.options + s.options
  1129. t.guards.beSmart = optStaticBoundsCheck in t.currOptions
  1130. t.locked = @[]
  1131. t.graph = g
  1132. t.config = g.config
  1133. t.c = c
  1134. proc hasRealBody(s: PSym): bool =
  1135. ## also handles importc procs with runnableExamples, which requires `=`,
  1136. ## which is not a real implementation, refs #14314
  1137. result = {sfForward, sfImportc} * s.flags == {}
  1138. proc trackProc*(c: PContext; s: PSym, body: PNode) =
  1139. let g = c.graph
  1140. var effects = s.typ.n[0]
  1141. if effects.kind != nkEffectList: return
  1142. # effects already computed?
  1143. if not s.hasRealBody: return
  1144. if effects.len == effectListLen: return
  1145. var t: TEffects
  1146. initEffects(g, effects, s, t, c)
  1147. track(t, body)
  1148. if s.kind != skMacro:
  1149. let params = s.typ.n
  1150. for i in 1..<params.len:
  1151. let param = params[i].sym
  1152. let typ = param.typ
  1153. if isSinkTypeForParam(typ) or
  1154. (t.config.selectedGC in {gcArc, gcOrc} and isClosure(typ.skipTypes(abstractInst))):
  1155. createTypeBoundOps(t, typ, param.info)
  1156. when false:
  1157. if typ.kind == tyOut and param.id notin t.init:
  1158. message(g.config, param.info, warnProveInit, param.name.s)
  1159. if not isEmptyType(s.typ[0]) and
  1160. (s.typ[0].requiresInit or s.typ[0].skipTypes(abstractInst).kind == tyVar) and
  1161. s.kind in {skProc, skFunc, skConverter, skMethod}:
  1162. var res = s.ast[resultPos].sym # get result symbol
  1163. if res.id notin t.init:
  1164. message(g.config, body.info, warnProveInit, "result")
  1165. let p = s.ast[pragmasPos]
  1166. let raisesSpec = effectSpec(p, wRaises)
  1167. if not isNil(raisesSpec):
  1168. checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
  1169. hints=on, subtypeRelation, hintsArg=s.ast[0])
  1170. # after the check, use the formal spec:
  1171. effects[exceptionEffects] = raisesSpec
  1172. let tagsSpec = effectSpec(p, wTags)
  1173. if not isNil(tagsSpec):
  1174. checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
  1175. hints=off, subtypeRelation)
  1176. # after the check, use the formal spec:
  1177. effects[tagEffects] = tagsSpec
  1178. let requiresSpec = propSpec(p, wRequires)
  1179. if not isNil(requiresSpec):
  1180. effects[requiresEffects] = requiresSpec
  1181. let ensuresSpec = propSpec(p, wEnsures)
  1182. if not isNil(ensuresSpec):
  1183. patchResult(t, ensuresSpec)
  1184. effects[ensuresEffects] = ensuresSpec
  1185. var mutationInfo = MutationInfo()
  1186. if {strictFuncs, views} * c.features != {}:
  1187. var goals: set[Goal] = {}
  1188. if strictFuncs in c.features: goals.incl constParameters
  1189. if views in c.features: goals.incl borrowChecking
  1190. var partitions = computeGraphPartitions(s, body, g.config, goals)
  1191. if not t.hasSideEffect and t.hasDangerousAssign:
  1192. t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo)
  1193. if views in c.features:
  1194. checkBorrowedLocations(partitions, body, g.config)
  1195. if sfThread in s.flags and t.gcUnsafe:
  1196. if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
  1197. #localError(s.info, "'$1' is not GC-safe" % s.name.s)
  1198. listGcUnsafety(s, onlyWarning=false, g.config)
  1199. else:
  1200. listGcUnsafety(s, onlyWarning=true, g.config)
  1201. #localError(s.info, warnGcUnsafe2, s.name.s)
  1202. if sfNoSideEffect in s.flags and t.hasSideEffect:
  1203. when false:
  1204. listGcUnsafety(s, onlyWarning=false, g.config)
  1205. else:
  1206. localError(g.config, s.info, ("'$1' can have side effects" % s.name.s) & (g.config $ mutationInfo))
  1207. if not t.gcUnsafe:
  1208. s.typ.flags.incl tfGcSafe
  1209. if not t.hasSideEffect and sfSideEffect notin s.flags:
  1210. s.typ.flags.incl tfNoSideEffect
  1211. if s.typ.lockLevel == UnspecifiedLockLevel:
  1212. s.typ.lockLevel = t.maxLockLevel
  1213. elif t.maxLockLevel > s.typ.lockLevel:
  1214. #localError(s.info,
  1215. message(g.config, s.info, warnLockLevel,
  1216. "declared lock level is $1, but real lock level is $2" %
  1217. [$s.typ.lockLevel, $t.maxLockLevel])
  1218. when defined(drnim):
  1219. if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, s, body)
  1220. when defined(useDfa):
  1221. if s.name.s == "testp":
  1222. dataflowAnalysis(s, body)
  1223. when false: trackWrites(s, body)
  1224. proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) =
  1225. if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
  1226. nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
  1227. return
  1228. let g = c.graph
  1229. var effects = newNodeI(nkEffectList, n.info)
  1230. var t: TEffects
  1231. initEffects(g, effects, module, t, c)
  1232. t.isTopLevel = isTopLevel
  1233. track(t, n)
  1234. when defined(drnim):
  1235. if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, module, n)