sempass2.nim 59 KB

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