sempass2.nim 65 KB

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