sempass2.nim 47 KB

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