sempass2.nim 65 KB

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