transf.nim 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  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. # This module implements the transformator. It transforms the syntax tree
  10. # to ease the work of the code generators. Does some transformations:
  11. #
  12. # * inlines iterators
  13. # * inlines constants
  14. # * performs constant folding
  15. # * converts "continue" to "break"; disambiguates "break"
  16. # * introduces method dispatchers
  17. # * performs lambda lifting for closure support
  18. # * transforms 'defer' into a 'try finally' statement
  19. import
  20. intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
  21. idents, renderer, types, passes, semfold, magicsys, cgmeth,
  22. sempass2, lowerings, destroyer, liftlocals,
  23. modulegraphs, lineinfos
  24. proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
  25. import closureiters, lambdalifting
  26. type
  27. PTransNode* = distinct PNode
  28. PTransCon = ref TTransCon
  29. TTransCon{.final.} = object # part of TContext; stackable
  30. mapping: TIdNodeTable # mapping from symbols to nodes
  31. owner: PSym # current owner
  32. forStmt: PNode # current for stmt
  33. forLoopBody: PTransNode # transformed for loop body
  34. yieldStmts: int # we count the number of yield statements,
  35. # because we need to introduce new variables
  36. # if we encounter the 2nd yield statement
  37. next: PTransCon # for stacking
  38. TTransfContext = object of TPassContext
  39. module: PSym
  40. transCon: PTransCon # top of a TransCon stack
  41. inlining: int # > 0 if we are in inlining context (copy vars)
  42. nestedProcs: int # > 0 if we are in a nested proc
  43. contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
  44. deferDetected, tooEarly, needsDestroyPass: bool
  45. graph: ModuleGraph
  46. PTransf = ref TTransfContext
  47. proc newTransNode(a: PNode): PTransNode {.inline.} =
  48. result = PTransNode(shallowCopy(a))
  49. proc newTransNode(kind: TNodeKind, info: TLineInfo,
  50. sons: int): PTransNode {.inline.} =
  51. var x = newNodeI(kind, info)
  52. newSeq(x.sons, sons)
  53. result = x.PTransNode
  54. proc newTransNode(kind: TNodeKind, n: PNode,
  55. sons: int): PTransNode {.inline.} =
  56. var x = newNodeIT(kind, n.info, n.typ)
  57. newSeq(x.sons, sons)
  58. x.typ = n.typ
  59. # x.flags = n.flags
  60. result = x.PTransNode
  61. proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
  62. proc len(a: PTransNode): int {.inline.} = sonsLen(a.PNode)
  63. proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
  64. var n = PNode(a)
  65. n.sons[i] = PNode(x)
  66. proc `[]=`(a: PTransNode, i: BackwardsIndex, x: PTransNode) {.inline.} =
  67. `[]=`(a, a.len - i.int, x)
  68. proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
  69. var n = PNode(a)
  70. result = n.sons[i].PTransNode
  71. proc `[]`(a: PTransNode, i: BackwardsIndex): PTransNode {.inline.} =
  72. `[]`(a, a.len - i.int)
  73. proc newTransCon(owner: PSym): PTransCon =
  74. assert owner != nil
  75. new(result)
  76. initIdNodeTable(result.mapping)
  77. result.owner = owner
  78. proc pushTransCon(c: PTransf, t: PTransCon) =
  79. t.next = c.transCon
  80. c.transCon = t
  81. proc popTransCon(c: PTransf) =
  82. if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
  83. c.transCon = c.transCon.next
  84. proc getCurrOwner(c: PTransf): PSym =
  85. if c.transCon != nil: result = c.transCon.owner
  86. else: result = c.module
  87. proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
  88. let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), getCurrOwner(c), info)
  89. r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
  90. incl(r.flags, sfFromGeneric)
  91. let owner = getCurrOwner(c)
  92. if owner.isIterator and not c.tooEarly:
  93. result = freshVarForClosureIter(c.graph, r, owner)
  94. else:
  95. result = newSymNode(r)
  96. proc transform(c: PTransf, n: PNode): PTransNode
  97. proc transformSons(c: PTransf, n: PNode): PTransNode =
  98. result = newTransNode(n)
  99. for i in countup(0, sonsLen(n)-1):
  100. result[i] = transform(c, n.sons[i])
  101. proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PTransNode): PTransNode =
  102. result = newTransNode(kind, PNode(ri).info, 2)
  103. result[0] = PTransNode(le)
  104. result[1] = ri
  105. proc transformSymAux(c: PTransf, n: PNode): PNode =
  106. let s = n.sym
  107. if s.typ != nil and s.typ.callConv == ccClosure:
  108. if s.kind in routineKinds:
  109. discard transformBody(c.graph, s)
  110. if s.kind == skIterator:
  111. if c.tooEarly: return n
  112. else: return liftIterSym(c.graph, n, getCurrOwner(c))
  113. elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
  114. # top level .closure procs are still somewhat supported for 'Nake':
  115. return makeClosure(c.graph, s, nil, n.info)
  116. #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
  117. # echo n.info, " come heer for ", c.tooEarly
  118. # if not c.tooEarly:
  119. var b: PNode
  120. var tc = c.transCon
  121. if sfBorrow in s.flags and s.kind in routineKinds:
  122. # simply exchange the symbol:
  123. b = s.getBody
  124. if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
  125. b = newSymNode(b.sym, n.info)
  126. else:
  127. b = n
  128. while tc != nil:
  129. result = idNodeTableGet(tc.mapping, b.sym)
  130. if result != nil:
  131. # this slightly convoluted way ensures the line info stays correct:
  132. if result.kind == nkSym:
  133. result = copyNode(result)
  134. result.info = n.info
  135. return
  136. tc = tc.next
  137. result = b
  138. proc transformSym(c: PTransf, n: PNode): PTransNode =
  139. result = PTransNode(transformSymAux(c, n))
  140. proc freshVar(c: PTransf; v: PSym): PNode =
  141. let owner = getCurrOwner(c)
  142. if owner.isIterator and not c.tooEarly:
  143. result = freshVarForClosureIter(c.graph, v, owner)
  144. else:
  145. var newVar = copySym(v)
  146. incl(newVar.flags, sfFromGeneric)
  147. newVar.owner = owner
  148. result = newSymNode(newVar)
  149. proc transformVarSection(c: PTransf, v: PNode): PTransNode =
  150. result = newTransNode(v)
  151. for i in countup(0, sonsLen(v)-1):
  152. var it = v.sons[i]
  153. if it.kind == nkCommentStmt:
  154. result[i] = PTransNode(it)
  155. elif it.kind == nkIdentDefs:
  156. if it.sons[0].kind == nkSym:
  157. internalAssert(c.graph.config, it.len == 3)
  158. let x = freshVar(c, it.sons[0].sym)
  159. idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
  160. var defs = newTransNode(nkIdentDefs, it.info, 3)
  161. if importantComments(c.graph.config):
  162. # keep documentation information:
  163. PNode(defs).comment = it.comment
  164. defs[0] = x.PTransNode
  165. defs[1] = it.sons[1].PTransNode
  166. defs[2] = transform(c, it.sons[2])
  167. if x.kind == nkSym: x.sym.ast = defs[2].PNode
  168. result[i] = defs
  169. else:
  170. # has been transformed into 'param.x' for closure iterators, so just
  171. # transform it:
  172. result[i] = transform(c, it)
  173. else:
  174. if it.kind != nkVarTuple:
  175. internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
  176. var L = sonsLen(it)
  177. var defs = newTransNode(it.kind, it.info, L)
  178. for j in countup(0, L-3):
  179. if it[j].kind == nkSym:
  180. let x = freshVar(c, it.sons[j].sym)
  181. idNodeTablePut(c.transCon.mapping, it.sons[j].sym, x)
  182. defs[j] = x.PTransNode
  183. else:
  184. defs[j] = transform(c, it[j])
  185. assert(it.sons[L-2].kind == nkEmpty)
  186. defs[L-2] = newNodeI(nkEmpty, it.info).PTransNode
  187. defs[L-1] = transform(c, it.sons[L-1])
  188. result[i] = defs
  189. proc transformConstSection(c: PTransf, v: PNode): PTransNode =
  190. result = PTransNode(v)
  191. when false:
  192. result = newTransNode(v)
  193. for i in countup(0, sonsLen(v)-1):
  194. var it = v.sons[i]
  195. if it.kind == nkCommentStmt:
  196. result[i] = PTransNode(it)
  197. else:
  198. if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
  199. if it.sons[0].kind != nkSym:
  200. debug it.sons[0]
  201. internalError(c.graph.config, it.info, "transformConstSection")
  202. result[i] = PTransNode(it)
  203. proc hasContinue(n: PNode): bool =
  204. case n.kind
  205. of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
  206. of nkContinueStmt: result = true
  207. else:
  208. for i in countup(0, sonsLen(n) - 1):
  209. if hasContinue(n.sons[i]): return true
  210. proc newLabel(c: PTransf, n: PNode): PSym =
  211. result = newSym(skLabel, nil, getCurrOwner(c), n.info)
  212. result.name = getIdent(c.graph.cache, genPrefix & $result.id)
  213. proc transformBlock(c: PTransf, n: PNode): PTransNode =
  214. var labl: PSym
  215. if c.inlining > 0:
  216. labl = newLabel(c, n[0])
  217. idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
  218. else:
  219. labl =
  220. if n.sons[0].kind != nkEmpty:
  221. n.sons[0].sym # already named block? -> Push symbol on the stack
  222. else:
  223. newLabel(c, n)
  224. c.breakSyms.add(labl)
  225. result = transformSons(c, n)
  226. discard c.breakSyms.pop
  227. result[0] = newSymNode(labl).PTransNode
  228. proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
  229. # What if it contains "continue" and "break"? "break" needs
  230. # an explicit label too, but not the same!
  231. # We fix this here by making every 'break' belong to its enclosing loop
  232. # and changing all breaks that belong to a 'block' by annotating it with
  233. # a label (if it hasn't one already).
  234. if hasContinue(n):
  235. let labl = newLabel(c, n)
  236. c.contSyms.add(labl)
  237. result = newTransNode(nkBlockStmt, n.info, 2)
  238. result[0] = newSymNode(labl).PTransNode
  239. result[1] = transform(c, n)
  240. discard c.contSyms.pop()
  241. else:
  242. result = transform(c, n)
  243. proc transformWhile(c: PTransf; n: PNode): PTransNode =
  244. if c.inlining > 0:
  245. result = transformSons(c, n)
  246. else:
  247. let labl = newLabel(c, n)
  248. c.breakSyms.add(labl)
  249. result = newTransNode(nkBlockStmt, n.info, 2)
  250. result[0] = newSymNode(labl).PTransNode
  251. var body = newTransNode(n)
  252. for i in 0..n.len-2:
  253. body[i] = transform(c, n.sons[i])
  254. body[n.len-1] = transformLoopBody(c, n.sons[n.len-1])
  255. result[1] = body
  256. discard c.breakSyms.pop
  257. proc transformBreak(c: PTransf, n: PNode): PTransNode =
  258. result = transformSons(c, n)
  259. if n.sons[0].kind == nkEmpty and c.breakSyms.len > 0:
  260. let labl = c.breakSyms[c.breakSyms.high]
  261. result[0] = newSymNode(labl).PTransNode
  262. proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
  263. case n.kind
  264. of nkSym:
  265. result = transformSym(c, n)
  266. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
  267. # nothing to be done for leaves:
  268. result = PTransNode(n)
  269. of nkVarSection, nkLetSection:
  270. result = transformVarSection(c, n)
  271. of nkClosure:
  272. # it can happen that for-loop-inlining produced a fresh
  273. # set of variables, including some computed environment
  274. # (bug #2604). We need to patch this environment here too:
  275. let a = n[1]
  276. if a.kind == nkSym:
  277. n.sons[1] = transformSymAux(c, a)
  278. return PTransNode(n)
  279. else:
  280. result = newTransNode(n)
  281. for i in countup(0, sonsLen(n)-1):
  282. result[i] = introduceNewLocalVars(c, n.sons[i])
  283. proc transformYield(c: PTransf, n: PNode): PTransNode =
  284. proc asgnTo(lhs: PNode, rhs: PTransNode): PTransNode =
  285. # Choose the right assignment instruction according to the given ``lhs``
  286. # node since it may not be a nkSym (a stack-allocated skForVar) but a
  287. # nkDotExpr (a heap-allocated slot into the envP block)
  288. case lhs.kind:
  289. of nkSym:
  290. internalAssert c.graph.config, lhs.sym.kind == skForVar
  291. result = newAsgnStmt(c, nkFastAsgn, lhs, rhs)
  292. of nkDotExpr:
  293. result = newAsgnStmt(c, nkAsgn, lhs, rhs)
  294. else:
  295. internalAssert c.graph.config, false
  296. result = newTransNode(nkStmtList, n.info, 0)
  297. var e = n.sons[0]
  298. # c.transCon.forStmt.len == 3 means that there is one for loop variable
  299. # and thus no tuple unpacking:
  300. if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
  301. if skipTypes(e.typ, {tyGenericInst, tyAlias, tySink}).kind == tyTuple and
  302. c.transCon.forStmt.len != 3:
  303. e = skipConv(e)
  304. if e.kind in {nkPar, nkTupleConstr}:
  305. for i in countup(0, sonsLen(e) - 1):
  306. var v = e.sons[i]
  307. if v.kind == nkExprColonExpr: v = v.sons[1]
  308. let lhs = c.transCon.forStmt.sons[i]
  309. let rhs = transform(c, v)
  310. add(result, asgnTo(lhs, rhs))
  311. else:
  312. # Unpack the tuple into the loop variables
  313. # XXX: BUG: what if `n` is an expression with side-effects?
  314. for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
  315. let lhs = c.transCon.forStmt.sons[i]
  316. let rhs = transform(c, newTupleAccess(c.graph, e, i))
  317. add(result, asgnTo(lhs, rhs))
  318. else:
  319. let lhs = c.transCon.forStmt.sons[0]
  320. let rhs = transform(c, e)
  321. add(result, asgnTo(lhs, rhs))
  322. inc(c.transCon.yieldStmts)
  323. if c.transCon.yieldStmts <= 1:
  324. # common case
  325. add(result, c.transCon.forLoopBody)
  326. else:
  327. # we need to introduce new local variables:
  328. add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
  329. proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
  330. result = transformSons(c, n)
  331. if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
  332. var n = result.PNode
  333. case n.sons[0].kind
  334. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  335. var m = n.sons[0].sons[0]
  336. if m.kind == a or m.kind == b:
  337. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  338. n.sons[0].sons[0] = m.sons[0]
  339. result = PTransNode(n.sons[0])
  340. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  341. PNode(result).typ = n.typ
  342. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  343. PNode(result).typ = toVar(PNode(result).typ)
  344. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  345. var m = n.sons[0].sons[1]
  346. if m.kind == a or m.kind == b:
  347. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  348. n.sons[0].sons[1] = m.sons[0]
  349. result = PTransNode(n.sons[0])
  350. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  351. PNode(result).typ = n.typ
  352. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  353. PNode(result).typ = toVar(PNode(result).typ)
  354. else:
  355. if n.sons[0].kind == a or n.sons[0].kind == b:
  356. # addr ( deref ( x )) --> x
  357. result = PTransNode(n.sons[0].sons[0])
  358. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  359. PNode(result).typ = n.typ
  360. proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
  361. ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
  362. ## a closure.
  363. # we cannot generate a proper thunk here for GC-safety reasons
  364. # (see internal documentation):
  365. if c.graph.config.cmd == cmdCompileToJS: return prc
  366. result = newNodeIT(nkClosure, prc.info, dest)
  367. var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
  368. conv.add(newNodeI(nkEmpty, prc.info))
  369. conv.add(prc)
  370. if prc.kind == nkClosure:
  371. internalError(c.graph.config, prc.info, "closure to closure created")
  372. result.add(conv)
  373. result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
  374. proc transformConv(c: PTransf, n: PNode): PTransNode =
  375. # numeric types need range checks:
  376. var dest = skipTypes(n.typ, abstractVarRange)
  377. var source = skipTypes(n.sons[1].typ, abstractVarRange)
  378. case dest.kind
  379. of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
  380. # we don't include uint and uint64 here as these are no ordinal types ;-)
  381. if not isOrdinalType(source):
  382. # float -> int conversions. ugh.
  383. result = transformSons(c, n)
  384. elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n.sons[1].typ) and
  385. lastOrd(c.graph.config, n.sons[1].typ) <= lastOrd(c.graph.config, n.typ):
  386. # BUGFIX: simply leave n as it is; we need a nkConv node,
  387. # but no range check:
  388. result = transformSons(c, n)
  389. else:
  390. # generate a range check:
  391. if dest.kind == tyInt64 or source.kind == tyInt64:
  392. result = newTransNode(nkChckRange64, n, 3)
  393. else:
  394. result = newTransNode(nkChckRange, n, 3)
  395. dest = skipTypes(n.typ, abstractVar)
  396. result[0] = transform(c, n.sons[1])
  397. result[1] = newIntTypeNode(nkIntLit, firstOrd(c.graph.config, dest), dest).PTransNode
  398. result[2] = newIntTypeNode(nkIntLit, lastOrd(c.graph.config, dest), dest).PTransNode
  399. of tyFloat..tyFloat128:
  400. # XXX int64 -> float conversion?
  401. if skipTypes(n.typ, abstractVar).kind == tyRange:
  402. result = newTransNode(nkChckRangeF, n, 3)
  403. dest = skipTypes(n.typ, abstractVar)
  404. result[0] = transform(c, n.sons[1])
  405. result[1] = copyTree(dest.n.sons[0]).PTransNode
  406. result[2] = copyTree(dest.n.sons[1]).PTransNode
  407. else:
  408. result = transformSons(c, n)
  409. of tyOpenArray, tyVarargs:
  410. result = transform(c, n.sons[1])
  411. PNode(result).typ = takeType(n.typ, n.sons[1].typ)
  412. #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
  413. # " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
  414. of tyCString:
  415. if source.kind == tyString:
  416. result = newTransNode(nkStringToCString, n, 1)
  417. result[0] = transform(c, n.sons[1])
  418. else:
  419. result = transformSons(c, n)
  420. of tyString:
  421. if source.kind == tyCString:
  422. result = newTransNode(nkCStringToString, n, 1)
  423. result[0] = transform(c, n.sons[1])
  424. else:
  425. result = transformSons(c, n)
  426. of tyRef, tyPtr:
  427. dest = skipTypes(dest, abstractPtrs)
  428. source = skipTypes(source, abstractPtrs)
  429. if source.kind == tyObject:
  430. var diff = inheritanceDiff(dest, source)
  431. if diff < 0:
  432. result = newTransNode(nkObjUpConv, n, 1)
  433. result[0] = transform(c, n.sons[1])
  434. elif diff > 0 and diff != high(int):
  435. result = newTransNode(nkObjDownConv, n, 1)
  436. result[0] = transform(c, n.sons[1])
  437. else:
  438. result = transform(c, n.sons[1])
  439. else:
  440. result = transformSons(c, n)
  441. of tyObject:
  442. var diff = inheritanceDiff(dest, source)
  443. if diff < 0:
  444. result = newTransNode(nkObjUpConv, n, 1)
  445. result[0] = transform(c, n.sons[1])
  446. elif diff > 0 and diff != high(int):
  447. result = newTransNode(nkObjDownConv, n, 1)
  448. result[0] = transform(c, n.sons[1])
  449. else:
  450. result = transform(c, n.sons[1])
  451. of tyGenericParam, tyOrdinal:
  452. result = transform(c, n.sons[1])
  453. # happens sometimes for generated assignments, etc.
  454. of tyProc:
  455. result = transformSons(c, n)
  456. if dest.callConv == ccClosure and source.callConv == ccDefault:
  457. result = generateThunk(c, result[1].PNode, dest).PTransNode
  458. else:
  459. result = transformSons(c, n)
  460. type
  461. TPutArgInto = enum
  462. paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
  463. proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
  464. # This analyses how to treat the mapping "formal <-> arg" in an
  465. # inline context.
  466. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
  467. if arg.kind == nkStmtListExpr:
  468. return paComplexOpenarray
  469. return paDirectMapping # XXX really correct?
  470. # what if ``arg`` has side-effects?
  471. case arg.kind
  472. of nkEmpty..nkNilLit:
  473. result = paDirectMapping
  474. of nkPar, nkTupleConstr, nkCurly, nkBracket:
  475. result = paFastAsgn
  476. for i in countup(0, sonsLen(arg) - 1):
  477. if putArgInto(arg.sons[i], formal) != paDirectMapping: return
  478. result = paDirectMapping
  479. else:
  480. if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
  481. else: result = paFastAsgn
  482. proc findWrongOwners(c: PTransf, n: PNode) =
  483. if n.kind == nkVarSection:
  484. let x = n.sons[0].sons[0]
  485. if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
  486. internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
  487. x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
  488. else:
  489. for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
  490. proc transformFor(c: PTransf, n: PNode): PTransNode =
  491. # generate access statements for the parameters (unless they are constant)
  492. # put mapping from formal parameters to actual parameters
  493. if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
  494. var length = sonsLen(n)
  495. var call = n.sons[length - 2]
  496. let labl = newLabel(c, n)
  497. result = newTransNode(nkBlockStmt, n.info, 2)
  498. result[0] = newSymNode(labl).PTransNode
  499. if call.typ.isNil:
  500. # see bug #3051
  501. result[1] = newNode(nkEmpty).PTransNode
  502. return result
  503. c.breakSyms.add(labl)
  504. if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
  505. call.sons[0].typ.callConv == ccClosure:
  506. result[1] = n.PTransNode
  507. result[1][^1] = transformLoopBody(c, n[^1])
  508. result[1][^2] = transform(c, n[^2])
  509. result[1] = lambdalifting.liftForLoop(c.graph, result[1].PNode, getCurrOwner(c)).PTransNode
  510. discard c.breakSyms.pop
  511. return result
  512. #echo "transforming: ", renderTree(n)
  513. var stmtList = newTransNode(nkStmtList, n.info, 0)
  514. result[1] = stmtList
  515. var loopBody = transformLoopBody(c, n.sons[length-1])
  516. discard c.breakSyms.pop
  517. var v = newNodeI(nkVarSection, n.info)
  518. for i in countup(0, length - 3):
  519. addVar(v, copyTree(n.sons[i])) # declare new vars
  520. add(stmtList, v.PTransNode)
  521. # Bugfix: inlined locals belong to the invoking routine, not to the invoked
  522. # iterator!
  523. let iter = call.sons[0].sym
  524. var newC = newTransCon(getCurrOwner(c))
  525. newC.forStmt = n
  526. newC.forLoopBody = loopBody
  527. # this can fail for 'nimsuggest' and 'check':
  528. if iter.kind != skIterator: return result
  529. # generate access statements for the parameters (unless they are constant)
  530. pushTransCon(c, newC)
  531. for i in countup(1, sonsLen(call) - 1):
  532. var arg = transform(c, call.sons[i]).PNode
  533. let ff = skipTypes(iter.typ, abstractInst)
  534. # can happen for 'nim check':
  535. if i >= ff.n.len: return result
  536. var formal = ff.n.sons[i].sym
  537. case putArgInto(arg, formal.typ)
  538. of paDirectMapping:
  539. idNodeTablePut(newC.mapping, formal, arg)
  540. of paFastAsgn:
  541. # generate a temporary and produce an assignment statement:
  542. var temp = newTemp(c, formal.typ, formal.info)
  543. addVar(v, temp)
  544. add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
  545. idNodeTablePut(newC.mapping, formal, temp)
  546. of paVarAsgn:
  547. assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
  548. idNodeTablePut(newC.mapping, formal, arg)
  549. # XXX BUG still not correct if the arg has a side effect!
  550. of paComplexOpenarray:
  551. let typ = newType(tySequence, formal.owner)
  552. addSonSkipIntLit(typ, formal.typ.sons[0])
  553. var temp = newTemp(c, typ, formal.info)
  554. addVar(v, temp)
  555. add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
  556. idNodeTablePut(newC.mapping, formal, temp)
  557. let body = transformBody(c.graph, iter)
  558. pushInfoContext(c.graph.config, n.info)
  559. inc(c.inlining)
  560. add(stmtList, transform(c, body))
  561. #findWrongOwners(c, stmtList.pnode)
  562. dec(c.inlining)
  563. popInfoContext(c.graph.config)
  564. popTransCon(c)
  565. # echo "transformed: ", stmtList.PNode.renderTree
  566. proc transformCase(c: PTransf, n: PNode): PTransNode =
  567. # removes `elif` branches of a case stmt
  568. # adds ``else: nil`` if needed for the code generator
  569. result = newTransNode(nkCaseStmt, n, 0)
  570. var ifs = PTransNode(nil)
  571. for i in 0 .. sonsLen(n)-1:
  572. var it = n.sons[i]
  573. var e = transform(c, it)
  574. case it.kind
  575. of nkElifBranch:
  576. if ifs.PNode == nil:
  577. # Generate the right node depending on whether `n` is used as a stmt or
  578. # as an expr
  579. let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
  580. ifs = newTransNode(kind, it.info, 0)
  581. ifs.PNode.typ = n.typ
  582. ifs.add(e)
  583. of nkElse:
  584. if ifs.PNode == nil: result.add(e)
  585. else: ifs.add(e)
  586. else:
  587. result.add(e)
  588. if ifs.PNode != nil:
  589. var elseBranch = newTransNode(nkElse, n.info, 1)
  590. elseBranch[0] = ifs
  591. result.add(elseBranch)
  592. elif result.PNode.lastSon.kind != nkElse and not (
  593. skipTypes(n.sons[0].typ, abstractVarRange).kind in
  594. {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}):
  595. # fix a stupid code gen bug by normalizing:
  596. var elseBranch = newTransNode(nkElse, n.info, 1)
  597. elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
  598. add(result, elseBranch)
  599. proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
  600. # XXX this is really bad; transf should use a proper AST visitor
  601. if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
  602. result = n.PTransNode
  603. else:
  604. result = newTransNode(n)
  605. for i in 0 ..< n.len:
  606. result[i] = transform(c, skipConv(n.sons[i]))
  607. proc getMergeOp(n: PNode): PSym =
  608. case n.kind
  609. of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
  610. nkCallStrLit:
  611. if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
  612. result = n.sons[0].sym
  613. else: discard
  614. proc flattenTreeAux(d, a: PNode, op: PSym) =
  615. let op2 = getMergeOp(a)
  616. if op2 != nil and
  617. (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
  618. for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
  619. else:
  620. addSon(d, copyTree(a))
  621. proc flattenTree(root: PNode): PNode =
  622. let op = getMergeOp(root)
  623. if op != nil:
  624. result = copyNode(root)
  625. addSon(result, copyTree(root.sons[0]))
  626. flattenTreeAux(result, root, op)
  627. else:
  628. result = root
  629. proc transformCall(c: PTransf, n: PNode): PTransNode =
  630. var n = flattenTree(n)
  631. let op = getMergeOp(n)
  632. let magic = getMagic(n)
  633. if op != nil and op.magic != mNone and n.len >= 3:
  634. result = newTransNode(nkCall, n, 0)
  635. add(result, transform(c, n.sons[0]))
  636. var j = 1
  637. while j < sonsLen(n):
  638. var a = transform(c, n.sons[j]).PNode
  639. inc(j)
  640. if isConstExpr(a):
  641. while (j < sonsLen(n)):
  642. let b = transform(c, n.sons[j]).PNode
  643. if not isConstExpr(b): break
  644. a = evalOp(op.magic, n, a, b, nil, c.graph)
  645. inc(j)
  646. add(result, a.PTransNode)
  647. if len(result) == 2: result = result[1]
  648. elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
  649. # for bindSym(myconst) we MUST NOT perform constant folding:
  650. result = n.PTransNode
  651. elif magic == mProcCall:
  652. # but do not change to its dispatcher:
  653. result = transformSons(c, n[1])
  654. else:
  655. let s = transformSons(c, n).PNode
  656. # bugfix: check after 'transformSons' if it's still a method call:
  657. # use the dispatcher for the call:
  658. if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod:
  659. when false:
  660. let t = lastSon(s.sons[0].sym.ast)
  661. if t.kind != nkSym or sfDispatcher notin t.sym.flags:
  662. methodDef(s.sons[0].sym, false)
  663. result = methodCall(s, c.graph.config).PTransNode
  664. else:
  665. result = s.PTransNode
  666. proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
  667. result = transformSons(c, n)
  668. if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
  669. let excTypeNode = n[0][1]
  670. let actions = newTransNode(nkStmtListExpr, n[1], 2)
  671. # Generating `let exc = (excType)(getCurrentException())`
  672. # -> getCurrentException()
  673. let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException"))
  674. # -> (excType)
  675. let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
  676. convNode[0] = PTransNode(newNodeI(nkEmpty, n.info))
  677. convNode[1] = excCall
  678. PNode(convNode).typ = excTypeNode.typ.toRef()
  679. # -> let exc = ...
  680. let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
  681. identDefs[0] = PTransNode(n[0][2])
  682. identDefs[1] = PTransNode(newNodeI(nkEmpty, n.info))
  683. identDefs[2] = convNode
  684. let letSection = newTransNode(nkLetSection, n[1].info, 1)
  685. letSection[0] = identDefs
  686. # Place the let statement and body of the 'except' branch into new stmtList.
  687. actions[0] = letSection
  688. actions[1] = transformSons(c, n[1])
  689. # Overwrite 'except' branch body with our stmtList.
  690. result[1] = actions
  691. # Replace the `Exception as foobar` with just `Exception`.
  692. result[0] = result[0][1]
  693. proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
  694. # symbols that expand to a complex constant (array, etc.) should not be
  695. # inlined, unless it's the empty array:
  696. result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
  697. cnst.len != 0
  698. proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
  699. result = n
  700. for i in 0 ..< n.safeLen:
  701. result.sons[i] = commonOptimizations(g, c, n.sons[i])
  702. var op = getMergeOp(n)
  703. if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
  704. result = newNodeIT(nkCall, n.info, n.typ)
  705. add(result, n.sons[0])
  706. var args = newNode(nkArgList)
  707. flattenTreeAux(args, n, op)
  708. var j = 0
  709. while j < sonsLen(args):
  710. var a = args.sons[j]
  711. inc(j)
  712. if isConstExpr(a):
  713. while j < sonsLen(args):
  714. let b = args.sons[j]
  715. if not isConstExpr(b): break
  716. a = evalOp(op.magic, result, a, b, nil, g)
  717. inc(j)
  718. add(result, a)
  719. if len(result) == 2: result = result[1]
  720. else:
  721. var cnst = getConstExpr(c, n, g)
  722. # we inline constants if they are not complex constants:
  723. if cnst != nil and not dontInlineConstant(n, cnst):
  724. result = cnst
  725. else:
  726. result = n
  727. proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNode =
  728. # This takes care of complicated signatures such as:
  729. # proc foo(a: int, b = a)
  730. # proc bar(a: int, b: int, c = a + b)
  731. #
  732. # The recursion may confuse you. It performs two duties:
  733. #
  734. # 1) extracting all referenced params from default expressions
  735. # into a let section preceeding the call
  736. #
  737. # 2) replacing the "references" within the default expression
  738. # with these extracted skLet symbols.
  739. #
  740. # The first duty is carried out directly in the code here, while the second
  741. # duty is activated by returning a non-nil value. The caller is responsible
  742. # for replacing the input to the function with the returned non-nil value.
  743. # (which is the hoisted symbol)
  744. if defExpr.kind == nkSym:
  745. if defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
  746. let paramPos = defExpr.sym.position + 1
  747. if call[paramPos].kind == nkSym and sfHoisted in call[paramPos].sym.flags:
  748. # Already hoisted, we still need to return it in order to replace the
  749. # placeholder expression in the default value.
  750. return call[paramPos]
  751. let hoistedVarSym = hoistExpr(letSection,
  752. call[paramPos],
  753. getIdent(c.graph.cache, genPrefix),
  754. c.transCon.owner).newSymNode
  755. call[paramPos] = hoistedVarSym
  756. return hoistedVarSym
  757. else:
  758. for i in 0..<defExpr.safeLen:
  759. let hoisted = hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
  760. if hoisted != nil: defExpr[i] = hoisted
  761. proc transform(c: PTransf, n: PNode): PTransNode =
  762. when false:
  763. var oldDeferAnchor: PNode
  764. if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
  765. nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
  766. nkBlockStmt, nkBlockExpr}:
  767. oldDeferAnchor = c.deferAnchor
  768. c.deferAnchor = n
  769. if n.typ != nil and tfHasAsgn in n.typ.flags:
  770. c.needsDestroyPass = true
  771. case n.kind
  772. of nkSym:
  773. result = transformSym(c, n)
  774. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
  775. # nothing to be done for leaves:
  776. result = PTransNode(n)
  777. of nkBracketExpr: result = transformArrayAccess(c, n)
  778. of procDefs:
  779. var s = n.sons[namePos].sym
  780. if n.typ != nil and s.typ.callConv == ccClosure:
  781. result = transformSym(c, n.sons[namePos])
  782. # use the same node as before if still a symbol:
  783. if result.PNode.kind == nkSym: result = PTransNode(n)
  784. else:
  785. result = PTransNode(n)
  786. of nkMacroDef:
  787. # XXX no proper closure support yet:
  788. when false:
  789. if n.sons[genericParamsPos].kind == nkEmpty:
  790. var s = n.sons[namePos].sym
  791. n.sons[bodyPos] = PNode(transform(c, s.getBody))
  792. if n.kind == nkMethodDef: methodDef(s, false)
  793. result = PTransNode(n)
  794. of nkForStmt:
  795. result = transformFor(c, n)
  796. of nkParForStmt:
  797. result = transformSons(c, n)
  798. of nkCaseStmt:
  799. result = transformCase(c, n)
  800. of nkWhileStmt: result = transformWhile(c, n)
  801. of nkBlockStmt, nkBlockExpr:
  802. result = transformBlock(c, n)
  803. of nkDefer:
  804. c.deferDetected = true
  805. result = transformSons(c, n)
  806. when false:
  807. let deferPart = newNodeI(nkFinally, n.info)
  808. deferPart.add n.sons[0]
  809. let tryStmt = newNodeI(nkTryStmt, n.info)
  810. if c.deferAnchor.isNil:
  811. tryStmt.add c.root
  812. c.root = tryStmt
  813. result = PTransNode(tryStmt)
  814. else:
  815. # modify the corresponding *action*, don't rely on nkStmtList:
  816. let L = c.deferAnchor.len-1
  817. tryStmt.add c.deferAnchor.sons[L]
  818. c.deferAnchor.sons[L] = tryStmt
  819. result = newTransNode(nkCommentStmt, n.info, 0)
  820. tryStmt.addSon(deferPart)
  821. # disable the original 'defer' statement:
  822. n.kind = nkEmpty
  823. of nkContinueStmt:
  824. result = PTransNode(newNodeI(nkBreakStmt, n.info))
  825. var labl = c.contSyms[c.contSyms.high]
  826. add(result, PTransNode(newSymNode(labl)))
  827. of nkBreakStmt: result = transformBreak(c, n)
  828. of nkCallKinds:
  829. result = transformCall(c, n)
  830. var call = result.PNode
  831. if nfDefaultRefsParam in call.flags:
  832. # We've found a default value that references another param.
  833. # See the notes in `hoistParamsUsedInDefault` for more details.
  834. var hoistedParams = newNodeI(nkLetSection, call.info, 0)
  835. for i in 1 ..< call.len:
  836. let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
  837. if hoisted != nil: call[i] = hoisted
  838. result = newTree(nkStmtListExpr, hoistedParams, call).PTransNode
  839. of nkAddr, nkHiddenAddr:
  840. result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
  841. of nkDerefExpr, nkHiddenDeref:
  842. result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
  843. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  844. result = transformConv(c, n)
  845. of nkDiscardStmt:
  846. result = PTransNode(n)
  847. if n.sons[0].kind != nkEmpty:
  848. result = transformSons(c, n)
  849. if isConstExpr(PNode(result).sons[0]):
  850. # ensure that e.g. discard "some comment" gets optimized away
  851. # completely:
  852. result = PTransNode(newNode(nkCommentStmt))
  853. of nkCommentStmt, nkTemplateDef, nkImportStmt, nkStaticStmt,
  854. nkExportStmt, nkExportExceptStmt:
  855. return n.PTransNode
  856. of nkConstSection:
  857. # do not replace ``const c = 3`` with ``const 3 = 3``
  858. return transformConstSection(c, n)
  859. of nkTypeSection, nkTypeOfExpr:
  860. # no need to transform type sections:
  861. return PTransNode(n)
  862. of nkVarSection, nkLetSection:
  863. if c.inlining > 0:
  864. # we need to copy the variables for multiple yield statements:
  865. result = transformVarSection(c, n)
  866. else:
  867. result = transformSons(c, n)
  868. of nkYieldStmt:
  869. if c.inlining > 0:
  870. result = transformYield(c, n)
  871. else:
  872. result = transformSons(c, n)
  873. of nkIdentDefs, nkConstDef:
  874. result = PTransNode(n)
  875. result[0] = transform(c, n[0])
  876. # Skip the second son since it only contains an unsemanticized copy of the
  877. # variable type used by docgen
  878. result[2] = transform(c, n[2])
  879. # XXX comment handling really sucks:
  880. if importantComments(c.graph.config):
  881. PNode(result).comment = n.comment
  882. of nkClosure:
  883. # it can happen that for-loop-inlining produced a fresh
  884. # set of variables, including some computed environment
  885. # (bug #2604). We need to patch this environment here too:
  886. let a = n[1]
  887. if a.kind == nkSym:
  888. n.sons[1] = transformSymAux(c, a)
  889. return PTransNode(n)
  890. of nkExceptBranch:
  891. result = transformExceptBranch(c, n)
  892. else:
  893. result = transformSons(c, n)
  894. when false:
  895. if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
  896. var cnst = getConstExpr(c.module, PNode(result), c.graph)
  897. # we inline constants if they are not complex constants:
  898. if cnst != nil and not dontInlineConstant(n, cnst):
  899. result = PTransNode(cnst) # do not miss an optimization
  900. proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
  901. # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
  902. # this step! We have to rely that the semantic pass transforms too errornous
  903. # nodes into an empty node.
  904. if nfTransf in n.flags: return n
  905. pushTransCon(c, newTransCon(owner))
  906. result = PNode(transform(c, n))
  907. popTransCon(c)
  908. incl(result.flags, nfTransf)
  909. proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
  910. new(result)
  911. result.contSyms = @[]
  912. result.breakSyms = @[]
  913. result.module = module
  914. result.graph = g
  915. proc flattenStmts(n: PNode) =
  916. var goOn = true
  917. while goOn:
  918. goOn = false
  919. var i = 0
  920. while i < n.len:
  921. let it = n[i]
  922. if it.kind in {nkStmtList, nkStmtListExpr}:
  923. n.sons[i..i] = it.sons[0..<it.len]
  924. goOn = true
  925. inc i
  926. proc liftDeferAux(n: PNode) =
  927. if n.kind in {nkStmtList, nkStmtListExpr}:
  928. flattenStmts(n)
  929. var goOn = true
  930. while goOn:
  931. goOn = false
  932. let last = n.len-1
  933. for i in 0..last:
  934. if n.sons[i].kind == nkDefer:
  935. let deferPart = newNodeI(nkFinally, n.sons[i].info)
  936. deferPart.add n.sons[i].sons[0]
  937. var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
  938. var body = newNodeI(n.kind, n.sons[i].info)
  939. if i < last:
  940. body.sons = n.sons[(i+1)..last]
  941. tryStmt.addSon(body)
  942. tryStmt.addSon(deferPart)
  943. n.sons[i] = tryStmt
  944. n.sons.setLen(i+1)
  945. n.typ = n.sons[i].typ
  946. goOn = true
  947. break
  948. for i in 0..n.safeLen-1:
  949. liftDeferAux(n.sons[i])
  950. template liftDefer(c, root) =
  951. if c.deferDetected:
  952. liftDeferAux(root)
  953. proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
  954. assert prc.kind in routineKinds
  955. if prc.transformedBody != nil:
  956. result = prc.transformedBody
  957. elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
  958. result = prc.ast[bodyPos]
  959. else:
  960. prc.transformedBody = newNode(nkEmpty) # protects from recursion
  961. var c = openTransf(g, prc.getModule, "")
  962. result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
  963. result = processTransf(c, result, prc)
  964. liftDefer(c, result)
  965. result = liftLocalsIfRequested(prc, result, g.cache, g.config)
  966. if c.needsDestroyPass: #and newDestructors:
  967. result = injectDestructorCalls(g, prc, result)
  968. if prc.isIterator:
  969. result = g.transformClosureIterator(prc, result)
  970. incl(result.flags, nfTransf)
  971. let cache = cache or prc.typ.callConv == ccInline
  972. if cache:
  973. # genProc for inline procs will be called multiple times from diffrent modules,
  974. # it is important to transform exactly once to get sym ids and locations right
  975. prc.transformedBody = result
  976. else:
  977. prc.transformedBody = nil
  978. proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  979. if nfTransf in n.flags:
  980. result = n
  981. else:
  982. var c = openTransf(g, module, "")
  983. result = processTransf(c, n, module)
  984. liftDefer(c, result)
  985. #result = liftLambdasForTopLevel(module, result)
  986. if c.needsDestroyPass:
  987. result = injectDestructorCalls(g, module, result)
  988. incl(result.flags, nfTransf)
  989. proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  990. if nfTransf in n.flags:
  991. result = n
  992. else:
  993. var c = openTransf(g, module, "")
  994. result = processTransf(c, n, module)
  995. liftDefer(c, result)
  996. # expressions are not to be injected with destructor calls as that
  997. # the list of top level statements needs to be collected before.
  998. if c.needsDestroyPass:
  999. result = injectDestructorCalls(g, module, result)
  1000. incl(result.flags, nfTransf)