sempass2.nim 47 KB

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