sempass2.nim 47 KB

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