transf.nim 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264
  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. options, ast, astalgo, trees, msgs,
  21. idents, renderer, types, semfold, magicsys, cgmeth,
  22. lowerings, liftlocals,
  23. modulegraphs, lineinfos
  24. when defined(nimPreviewSlimSystem):
  25. import std/assertions
  26. type
  27. TransformBodyFlag* = enum
  28. dontUseCache, useCache
  29. proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag, force = false): PNode
  30. import closureiters, lambdalifting
  31. type
  32. PTransCon = ref object # part of TContext; stackable
  33. mapping: TIdNodeTable # mapping from symbols to nodes
  34. owner: PSym # current owner
  35. forStmt: PNode # current for stmt
  36. forLoopBody: PNode # transformed for loop body
  37. yieldStmts: int # we count the number of yield statements,
  38. # because we need to introduce new variables
  39. # if we encounter the 2nd yield statement
  40. next: PTransCon # for stacking
  41. PTransf = ref object
  42. module: PSym
  43. transCon: PTransCon # top of a TransCon stack
  44. inlining: int # > 0 if we are in inlining context (copy vars)
  45. isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
  46. contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
  47. deferDetected, tooEarly: bool
  48. graph: ModuleGraph
  49. idgen: IdGenerator
  50. proc newTransNode(a: PNode): PNode {.inline.} =
  51. result = shallowCopy(a)
  52. proc newTransNode(kind: TNodeKind, info: TLineInfo,
  53. sons: int): PNode {.inline.} =
  54. var x = newNodeI(kind, info)
  55. newSeq(x.sons, sons)
  56. result = x
  57. proc newTransNode(kind: TNodeKind, n: PNode,
  58. sons: int): PNode {.inline.} =
  59. var x = newNodeIT(kind, n.info, n.typ)
  60. newSeq(x.sons, sons)
  61. # x.flags = n.flags
  62. result = x
  63. proc newTransCon(owner: PSym): PTransCon =
  64. assert owner != nil
  65. new(result)
  66. initIdNodeTable(result.mapping)
  67. result.owner = owner
  68. proc pushTransCon(c: PTransf, t: PTransCon) =
  69. t.next = c.transCon
  70. c.transCon = t
  71. proc popTransCon(c: PTransf) =
  72. if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
  73. c.transCon = c.transCon.next
  74. proc getCurrOwner(c: PTransf): PSym =
  75. if c.transCon != nil: result = c.transCon.owner
  76. else: result = c.module
  77. proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
  78. let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), c.idgen, getCurrOwner(c), info)
  79. r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
  80. incl(r.flags, sfFromGeneric)
  81. let owner = getCurrOwner(c)
  82. if owner.isIterator and not c.tooEarly:
  83. result = freshVarForClosureIter(c.graph, r, c.idgen, owner)
  84. else:
  85. result = newSymNode(r)
  86. proc transform(c: PTransf, n: PNode, noConstFold = false): PNode
  87. proc transformSons(c: PTransf, n: PNode, noConstFold = false): PNode =
  88. result = newTransNode(n)
  89. for i in 0..<n.len:
  90. result[i] = transform(c, n[i], noConstFold)
  91. proc transformSonsAfterType(c: PTransf, n: PNode, noConstFold = false): PNode =
  92. result = newTransNode(n)
  93. assert n.len != 0
  94. result[0] = copyTree(n[0])
  95. for i in 1..<n.len:
  96. result[i] = transform(c, n[i], noConstFold)
  97. proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite: bool): PNode =
  98. result = newTransNode(kind, ri.info, 2)
  99. result[0] = le
  100. if isFirstWrite:
  101. le.flags.incl nfFirstWrite
  102. result[1] = ri
  103. proc transformSymAux(c: PTransf, n: PNode): PNode =
  104. let s = n.sym
  105. if s.typ != nil and s.typ.callConv == ccClosure:
  106. if s.kind in routineKinds:
  107. discard transformBody(c.graph, c.idgen, s, useCache)
  108. if s.kind == skIterator:
  109. if c.tooEarly: return n
  110. else: return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c))
  111. elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
  112. # top level .closure procs are still somewhat supported for 'Nake':
  113. return makeClosure(c.graph, c.idgen, s, nil, n.info)
  114. #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
  115. # echo n.info, " come heer for ", c.tooEarly
  116. # if not c.tooEarly:
  117. var b: PNode
  118. var tc = c.transCon
  119. if sfBorrow in s.flags and s.kind in routineKinds:
  120. # simply exchange the symbol:
  121. var s = s
  122. while true:
  123. # Skips over all borrowed procs getting the last proc symbol without an implementation
  124. let body = getBody(c.graph, s)
  125. if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
  126. s = body.sym
  127. else:
  128. break
  129. b = getBody(c.graph, s)
  130. if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
  131. b = newSymNode(b.sym, n.info)
  132. elif c.inlining > 0:
  133. # see bug #13596: we use ref-based equality in the DFA for destruction
  134. # injections so we need to ensure unique nodes after iterator inlining
  135. # which can lead to duplicated for loop bodies! Consider:
  136. #[
  137. while remaining > 0:
  138. if ending == nil:
  139. yield ms
  140. break
  141. ...
  142. yield ms
  143. ]#
  144. b = newSymNode(n.sym, n.info)
  145. else:
  146. b = n
  147. while tc != nil:
  148. result = idNodeTableGet(tc.mapping, b.sym)
  149. if result != nil:
  150. # this slightly convoluted way ensures the line info stays correct:
  151. if result.kind == nkSym:
  152. result = copyNode(result)
  153. result.info = n.info
  154. return
  155. tc = tc.next
  156. result = b
  157. proc transformSym(c: PTransf, n: PNode): PNode =
  158. result = transformSymAux(c, n)
  159. proc freshVar(c: PTransf; v: PSym): PNode =
  160. let owner = getCurrOwner(c)
  161. if owner.isIterator and not c.tooEarly:
  162. result = freshVarForClosureIter(c.graph, v, c.idgen, owner)
  163. else:
  164. var newVar = copySym(v, c.idgen)
  165. incl(newVar.flags, sfFromGeneric)
  166. newVar.owner = owner
  167. result = newSymNode(newVar)
  168. proc transformVarSection(c: PTransf, v: PNode): PNode =
  169. result = newTransNode(v)
  170. for i in 0..<v.len:
  171. var it = v[i]
  172. if it.kind == nkCommentStmt:
  173. result[i] = it
  174. elif it.kind == nkIdentDefs:
  175. var vn = it[0]
  176. if vn.kind == nkPragmaExpr: vn = vn[0]
  177. if vn.kind == nkSym:
  178. internalAssert(c.graph.config, it.len == 3)
  179. let x = freshVar(c, vn.sym)
  180. idNodeTablePut(c.transCon.mapping, vn.sym, x)
  181. var defs = newTransNode(nkIdentDefs, it.info, 3)
  182. if importantComments(c.graph.config):
  183. # keep documentation information:
  184. defs.comment = it.comment
  185. defs[0] = x
  186. defs[1] = it[1]
  187. defs[2] = transform(c, it[2])
  188. if x.kind == nkSym: x.sym.ast = defs[2]
  189. result[i] = defs
  190. else:
  191. # has been transformed into 'param.x' for closure iterators, so just
  192. # transform it:
  193. result[i] = transform(c, it)
  194. else:
  195. if it.kind != nkVarTuple:
  196. internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
  197. var defs = newTransNode(it.kind, it.info, it.len)
  198. for j in 0..<it.len-2:
  199. if it[j].kind == nkSym:
  200. let x = freshVar(c, it[j].sym)
  201. idNodeTablePut(c.transCon.mapping, it[j].sym, x)
  202. defs[j] = x
  203. else:
  204. defs[j] = transform(c, it[j])
  205. assert(it[^2].kind == nkEmpty)
  206. defs[^2] = newNodeI(nkEmpty, it.info)
  207. defs[^1] = transform(c, it[^1])
  208. result[i] = defs
  209. proc transformConstSection(c: PTransf, v: PNode): PNode =
  210. result = v
  211. when false:
  212. result = newTransNode(v)
  213. for i in 0..<v.len:
  214. var it = v[i]
  215. if it.kind == nkCommentStmt:
  216. result[i] = it
  217. else:
  218. if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
  219. if it[0].kind != nkSym:
  220. debug it[0]
  221. internalError(c.graph.config, it.info, "transformConstSection")
  222. result[i] = it
  223. proc hasContinue(n: PNode): bool =
  224. case n.kind
  225. of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
  226. of nkContinueStmt: result = true
  227. else:
  228. for i in 0..<n.len:
  229. if hasContinue(n[i]): return true
  230. proc newLabel(c: PTransf, n: PNode): PSym =
  231. result = newSym(skLabel, getIdent(c.graph.cache, genPrefix), c.idgen, getCurrOwner(c), n.info)
  232. proc transformBlock(c: PTransf, n: PNode): PNode =
  233. var labl: PSym
  234. if c.inlining > 0:
  235. labl = newLabel(c, n[0])
  236. idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
  237. else:
  238. labl =
  239. if n[0].kind != nkEmpty:
  240. n[0].sym # already named block? -> Push symbol on the stack
  241. else:
  242. newLabel(c, n)
  243. c.breakSyms.add(labl)
  244. result = transformSons(c, n)
  245. discard c.breakSyms.pop
  246. result[0] = newSymNode(labl)
  247. proc transformLoopBody(c: PTransf, n: PNode): PNode =
  248. # What if it contains "continue" and "break"? "break" needs
  249. # an explicit label too, but not the same!
  250. # We fix this here by making every 'break' belong to its enclosing loop
  251. # and changing all breaks that belong to a 'block' by annotating it with
  252. # a label (if it hasn't one already).
  253. if hasContinue(n):
  254. let labl = newLabel(c, n)
  255. c.contSyms.add(labl)
  256. result = newTransNode(nkBlockStmt, n.info, 2)
  257. result[0] = newSymNode(labl)
  258. result[1] = transform(c, n)
  259. discard c.contSyms.pop()
  260. else:
  261. result = transform(c, n)
  262. proc transformWhile(c: PTransf; n: PNode): PNode =
  263. if c.inlining > 0:
  264. result = transformSons(c, n)
  265. else:
  266. let labl = newLabel(c, n)
  267. c.breakSyms.add(labl)
  268. result = newTransNode(nkBlockStmt, n.info, 2)
  269. result[0] = newSymNode(labl)
  270. var body = newTransNode(n)
  271. for i in 0..<n.len-1:
  272. body[i] = transform(c, n[i])
  273. body[^1] = transformLoopBody(c, n[^1])
  274. result[1] = body
  275. discard c.breakSyms.pop
  276. proc transformBreak(c: PTransf, n: PNode): PNode =
  277. result = transformSons(c, n)
  278. if n[0].kind == nkEmpty and c.breakSyms.len > 0:
  279. let labl = c.breakSyms[c.breakSyms.high]
  280. result[0] = newSymNode(labl)
  281. proc introduceNewLocalVars(c: PTransf, n: PNode): PNode =
  282. case n.kind
  283. of nkSym:
  284. result = transformSym(c, n)
  285. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
  286. # nothing to be done for leaves:
  287. result = n
  288. of nkVarSection, nkLetSection:
  289. result = transformVarSection(c, n)
  290. of nkClosure:
  291. # it can happen that for-loop-inlining produced a fresh
  292. # set of variables, including some computed environment
  293. # (bug #2604). We need to patch this environment here too:
  294. let a = n[1]
  295. if a.kind == nkSym:
  296. n[1] = transformSymAux(c, a)
  297. return n
  298. of nkProcDef: # todo optimize nosideeffects?
  299. result = newTransNode(n)
  300. let x = newSymNode(copySym(n[namePos].sym, c.idgen))
  301. idNodeTablePut(c.transCon.mapping, n[namePos].sym, x)
  302. result[namePos] = x # we have to copy proc definitions for iters
  303. for i in 1..<n.len:
  304. result[i] = introduceNewLocalVars(c, n[i])
  305. result[namePos].sym.ast = result
  306. else:
  307. result = newTransNode(n)
  308. for i in 0..<n.len:
  309. result[i] = introduceNewLocalVars(c, n[i])
  310. proc transformAsgn(c: PTransf, n: PNode): PNode =
  311. let rhs = n[1]
  312. if rhs.kind != nkTupleConstr:
  313. return transformSons(c, n)
  314. # Unpack the tuple assignment into N temporary variables and then pack them
  315. # into a tuple: this allows us to get the correct results even when the rhs
  316. # depends on the value of the lhs
  317. let letSection = newTransNode(nkLetSection, n.info, rhs.len)
  318. let newTupleConstr = newTransNode(nkTupleConstr, n.info, rhs.len)
  319. for i, field in rhs:
  320. let val = if field.kind == nkExprColonExpr: field[1] else: field
  321. let def = newTransNode(nkIdentDefs, field.info, 3)
  322. def[0] = newTemp(c, val.typ, field.info)
  323. def[1] = newNodeI(nkEmpty, field.info)
  324. def[2] = transform(c, val)
  325. letSection[i] = def
  326. # NOTE: We assume the constructor fields are in the correct order for the
  327. # given tuple type
  328. newTupleConstr[i] = def[0]
  329. newTupleConstr.typ = rhs.typ
  330. let asgnNode = newTransNode(nkAsgn, n.info, 2)
  331. asgnNode[0] = transform(c, n[0])
  332. asgnNode[1] = newTupleConstr
  333. result = newTransNode(nkStmtList, n.info, 2)
  334. result[0] = letSection
  335. result[1] = asgnNode
  336. proc transformYield(c: PTransf, n: PNode): PNode =
  337. proc asgnTo(lhs: PNode, rhs: PNode): PNode =
  338. # Choose the right assignment instruction according to the given ``lhs``
  339. # node since it may not be a nkSym (a stack-allocated skForVar) but a
  340. # nkDotExpr (a heap-allocated slot into the envP block)
  341. case lhs.kind
  342. of nkSym:
  343. internalAssert c.graph.config, lhs.sym.kind == skForVar
  344. result = newAsgnStmt(c, nkFastAsgn, lhs, rhs, false)
  345. of nkDotExpr:
  346. result = newAsgnStmt(c, nkAsgn, lhs, rhs, false)
  347. else:
  348. internalAssert c.graph.config, false
  349. result = newTransNode(nkStmtList, n.info, 0)
  350. var e = n[0]
  351. # c.transCon.forStmt.len == 3 means that there is one for loop variable
  352. # and thus no tuple unpacking:
  353. if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
  354. if c.transCon.forStmt.len != 3:
  355. e = skipConv(e)
  356. if e.kind == nkTupleConstr:
  357. for i in 0..<e.len:
  358. var v = e[i]
  359. if v.kind == nkExprColonExpr: v = v[1]
  360. if c.transCon.forStmt[i].kind == nkVarTuple:
  361. for j in 0..<c.transCon.forStmt[i].len-1:
  362. let lhs = c.transCon.forStmt[i][j]
  363. let rhs = transform(c, newTupleAccess(c.graph, v, j))
  364. result.add(asgnTo(lhs, rhs))
  365. else:
  366. let lhs = c.transCon.forStmt[i]
  367. let rhs = transform(c, v)
  368. result.add(asgnTo(lhs, rhs))
  369. elif e.kind notin {nkAddr, nkHiddenAddr}: # no need to generate temp for address operation
  370. # TODO do not use temp for nodes which cannot have side-effects
  371. var tmp = newTemp(c, e.typ, e.info)
  372. let v = newNodeI(nkVarSection, e.info)
  373. v.addVar(tmp, e)
  374. result.add transform(c, v)
  375. for i in 0..<c.transCon.forStmt.len - 2:
  376. let lhs = c.transCon.forStmt[i]
  377. let rhs = transform(c, newTupleAccess(c.graph, tmp, i))
  378. result.add(asgnTo(lhs, rhs))
  379. else:
  380. for i in 0..<c.transCon.forStmt.len - 2:
  381. let lhs = c.transCon.forStmt[i]
  382. let rhs = transform(c, newTupleAccess(c.graph, e, i))
  383. result.add(asgnTo(lhs, rhs))
  384. else:
  385. if c.transCon.forStmt[0].kind == nkVarTuple:
  386. var notLiteralTuple = false # we don't generate temp for tuples with const value: (1, 2, 3)
  387. let ev = e.skipConv
  388. if ev.kind == nkTupleConstr:
  389. for i in ev:
  390. if not isConstExpr(i):
  391. notLiteralTuple = true
  392. break
  393. else:
  394. notLiteralTuple = true
  395. if e.kind notin {nkAddr, nkHiddenAddr} and notLiteralTuple:
  396. # TODO do not use temp for nodes which cannot have side-effects
  397. var tmp = newTemp(c, e.typ, e.info)
  398. let v = newNodeI(nkVarSection, e.info)
  399. v.addVar(tmp, e)
  400. result.add transform(c, v)
  401. for i in 0..<c.transCon.forStmt[0].len-1:
  402. let lhs = c.transCon.forStmt[0][i]
  403. let rhs = transform(c, newTupleAccess(c.graph, tmp, i))
  404. result.add(asgnTo(lhs, rhs))
  405. else:
  406. for i in 0..<c.transCon.forStmt[0].len-1:
  407. let lhs = c.transCon.forStmt[0][i]
  408. let rhs = transform(c, newTupleAccess(c.graph, e, i))
  409. result.add(asgnTo(lhs, rhs))
  410. else:
  411. let lhs = c.transCon.forStmt[0]
  412. let rhs = transform(c, e)
  413. result.add(asgnTo(lhs, rhs))
  414. # bug #23536; note that the info of forLoopBody should't change
  415. for idx in 0 ..< result.len:
  416. var changeNode = result[idx]
  417. changeNode.info = c.transCon.forStmt.info
  418. for i, child in changeNode:
  419. child.info = changeNode.info
  420. inc(c.transCon.yieldStmts)
  421. if c.transCon.yieldStmts <= 1:
  422. # common case
  423. result.add(c.transCon.forLoopBody)
  424. else:
  425. # we need to introduce new local variables:
  426. c.isIntroducingNewLocalVars = true # don't transform yields when introducing new local vars
  427. result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
  428. c.isIntroducingNewLocalVars = false
  429. proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds, isAddr = false): PNode =
  430. result = transformSons(c, n, noConstFold = isAddr)
  431. # inlining of 'var openarray' iterators; bug #19977
  432. if n.typ.kind != tyOpenArray and (c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags): return
  433. var n = result
  434. case n[0].kind
  435. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  436. var m = n[0][0]
  437. if m.kind in kinds:
  438. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  439. n[0][0] = m[0]
  440. result = n[0]
  441. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  442. result.typ = n.typ
  443. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  444. result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
  445. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  446. var m = n[0][1]
  447. if m.kind in kinds:
  448. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  449. n[0][1] = m[0]
  450. result = n[0]
  451. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  452. result.typ = n.typ
  453. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  454. result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
  455. else:
  456. if n[0].kind in kinds and
  457. not (n[0][0].kind == nkSym and n[0][0].sym.kind == skForVar and
  458. n[0][0].typ.skipTypes(abstractVar).kind == tyTuple
  459. ) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
  460. n.typ.kind == tyVar and
  461. n.typ.skipTypes(abstractVar).kind == tyOpenArray and
  462. n[0][0].typ.skipTypes(abstractVar).kind == tyString) and
  463. not (isAddr and n.typ.kind == tyVar and n[0][0].typ.kind == tyRef and
  464. n[0][0].kind == nkObjConstr)
  465. : # elimination is harmful to `for tuple unpack` because of newTupleAccess
  466. # it is also harmful to openArrayLoc (var openArray) for strings
  467. # addr ( deref ( x )) --> x
  468. result = n[0][0]
  469. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  470. result.typ = n.typ
  471. proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
  472. ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
  473. ## a closure.
  474. # we cannot generate a proper thunk here for GC-safety reasons
  475. # (see internal documentation):
  476. if c.graph.config.backend == backendJs: return prc
  477. result = newNodeIT(nkClosure, prc.info, dest)
  478. var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
  479. conv.add(newNodeI(nkEmpty, prc.info))
  480. conv.add(prc)
  481. if prc.kind == nkClosure:
  482. internalError(c.graph.config, prc.info, "closure to closure created")
  483. result.add(conv)
  484. result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
  485. proc transformConv(c: PTransf, n: PNode): PNode =
  486. # numeric types need range checks:
  487. var dest = skipTypes(n.typ, abstractVarRange)
  488. var source = skipTypes(n[1].typ, abstractVarRange)
  489. case dest.kind
  490. of tyInt..tyInt64, tyEnum, tyChar, tyUInt8..tyUInt32:
  491. # we don't include uint and uint64 here as these are no ordinal types ;-)
  492. if not isOrdinalType(source):
  493. # float -> int conversions. ugh.
  494. result = transformSons(c, n)
  495. elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n[1].typ) and
  496. lastOrd(c.graph.config, n[1].typ) <= lastOrd(c.graph.config, n.typ):
  497. # BUGFIX: simply leave n as it is; we need a nkConv node,
  498. # but no range check:
  499. result = transformSons(c, n)
  500. else:
  501. # generate a range check:
  502. if dest.kind == tyInt64 or source.kind == tyInt64:
  503. result = newTransNode(nkChckRange64, n, 3)
  504. else:
  505. result = newTransNode(nkChckRange, n, 3)
  506. dest = skipTypes(n.typ, abstractVar)
  507. result[0] = transform(c, n[1])
  508. result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest)
  509. result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest)
  510. of tyFloat..tyFloat128:
  511. # XXX int64 -> float conversion?
  512. if skipTypes(n.typ, abstractVar).kind == tyRange:
  513. result = newTransNode(nkChckRangeF, n, 3)
  514. dest = skipTypes(n.typ, abstractVar)
  515. result[0] = transform(c, n[1])
  516. result[1] = copyTree(dest.n[0])
  517. result[2] = copyTree(dest.n[1])
  518. else:
  519. result = transformSons(c, n)
  520. of tyOpenArray, tyVarargs:
  521. result = transform(c, n[1])
  522. #result = transformSons(c, n)
  523. result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen)
  524. #echo n.info, " came here and produced ", typeToString(result.typ),
  525. # " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
  526. of tyCstring:
  527. if source.kind == tyString:
  528. result = newTransNode(nkStringToCString, n, 1)
  529. result[0] = transform(c, n[1])
  530. else:
  531. result = transformSons(c, n)
  532. of tyString:
  533. if source.kind == tyCstring:
  534. result = newTransNode(nkCStringToString, n, 1)
  535. result[0] = transform(c, n[1])
  536. else:
  537. result = transformSons(c, n)
  538. of tyRef, tyPtr:
  539. dest = skipTypes(dest, abstractPtrs)
  540. source = skipTypes(source, abstractPtrs)
  541. if source.kind == tyObject:
  542. var diff = inheritanceDiff(dest, source)
  543. if diff < 0:
  544. result = newTransNode(nkObjUpConv, n, 1)
  545. result[0] = transform(c, n[1])
  546. elif diff > 0 and diff != high(int):
  547. result = newTransNode(nkObjDownConv, n, 1)
  548. result[0] = transform(c, n[1])
  549. else:
  550. result = transform(c, n[1])
  551. result.typ = n.typ
  552. else:
  553. result = transformSons(c, n)
  554. of tyObject:
  555. var diff = inheritanceDiff(dest, source)
  556. if diff < 0:
  557. result = newTransNode(nkObjUpConv, n, 1)
  558. result[0] = transform(c, n[1])
  559. elif diff > 0 and diff != high(int):
  560. result = newTransNode(nkObjDownConv, n, 1)
  561. result[0] = transform(c, n[1])
  562. else:
  563. result = transform(c, n[1])
  564. result.typ = n.typ
  565. of tyGenericParam, tyOrdinal:
  566. result = transform(c, n[1])
  567. # happens sometimes for generated assignments, etc.
  568. of tyProc:
  569. result = transformSons(c, n)
  570. if dest.callConv == ccClosure and source.callConv == ccNimCall:
  571. result = generateThunk(c, result[1], dest)
  572. else:
  573. result = transformSons(c, n)
  574. type
  575. TPutArgInto = enum
  576. paDirectMapping, paFastAsgn, paFastAsgnTakeTypeFromArg
  577. paVarAsgn, paComplexOpenarray
  578. proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
  579. # This analyses how to treat the mapping "formal <-> arg" in an
  580. # inline context.
  581. if formal.kind == tyTypeDesc: return paDirectMapping
  582. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
  583. case arg.kind
  584. of nkStmtListExpr:
  585. return paComplexOpenarray
  586. of nkBracket:
  587. return paFastAsgnTakeTypeFromArg
  588. else:
  589. # XXX incorrect, causes #13417 when `arg` has side effects.
  590. return paDirectMapping
  591. case arg.kind
  592. of nkEmpty..nkNilLit:
  593. result = paDirectMapping
  594. of nkDotExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr:
  595. result = putArgInto(arg[0], formal)
  596. of nkCurly, nkBracket:
  597. for i in 0..<arg.len:
  598. if putArgInto(arg[i], formal) != paDirectMapping:
  599. return paFastAsgn
  600. result = paDirectMapping
  601. of nkPar, nkTupleConstr, nkObjConstr:
  602. for i in 0..<arg.len:
  603. let a = if arg[i].kind == nkExprColonExpr: arg[i][1]
  604. else: arg[0]
  605. if putArgInto(a, formal) != paDirectMapping:
  606. return paFastAsgn
  607. result = paDirectMapping
  608. else:
  609. if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
  610. else: result = paFastAsgn
  611. proc findWrongOwners(c: PTransf, n: PNode) =
  612. if n.kind == nkVarSection:
  613. let x = n[0][0]
  614. if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
  615. internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
  616. x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
  617. else:
  618. for i in 0..<n.safeLen: findWrongOwners(c, n[i])
  619. proc isSimpleIteratorVar(c: PTransf; iter: PSym; call: PNode; owner: PSym): bool =
  620. proc rec(n: PNode; owner: PSym; dangerousYields: var int) =
  621. case n.kind
  622. of nkEmpty..nkNilLit: discard
  623. of nkYieldStmt:
  624. if n[0].kind == nkSym and n[0].sym.owner == owner:
  625. discard "good: yield a single variable that we own"
  626. else:
  627. inc dangerousYields
  628. else:
  629. for c in n: rec(c, owner, dangerousYields)
  630. proc recSym(n: PNode; owner: PSym; sameOwner: var bool) =
  631. case n.kind
  632. of {nkEmpty..nkNilLit} - {nkSym}: discard
  633. of nkSym:
  634. if n.sym.owner != owner:
  635. sameOwner = false
  636. else:
  637. for c in n: recSym(c, owner, sameOwner)
  638. var dangerousYields = 0
  639. rec(getBody(c.graph, iter), iter, dangerousYields)
  640. result = dangerousYields == 0
  641. # the parameters should be owned by the owner
  642. # bug #22237
  643. for i in 1..<call.len:
  644. recSym(call[i], owner, result)
  645. template destructor(t: PType): PSym = getAttachedOp(c.graph, t, attachedDestructor)
  646. proc transformFor(c: PTransf, n: PNode): PNode =
  647. # generate access statements for the parameters (unless they are constant)
  648. # put mapping from formal parameters to actual parameters
  649. if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
  650. var call = n[^2]
  651. let labl = newLabel(c, n)
  652. result = newTransNode(nkBlockStmt, n.info, 2)
  653. result[0] = newSymNode(labl)
  654. if call.typ.isNil:
  655. # see bug #3051
  656. result[1] = newNode(nkEmpty)
  657. return result
  658. c.breakSyms.add(labl)
  659. if call.kind notin nkCallKinds or call[0].kind != nkSym or
  660. call[0].typ.skipTypes(abstractInst).callConv == ccClosure:
  661. result[1] = n
  662. result[1][^1] = transformLoopBody(c, n[^1])
  663. result[1][^2] = transform(c, n[^2])
  664. result[1] = lambdalifting.liftForLoop(c.graph, result[1], c.idgen, getCurrOwner(c))
  665. discard c.breakSyms.pop
  666. return result
  667. #echo "transforming: ", renderTree(n)
  668. var stmtList = newTransNode(nkStmtList, n.info, 0)
  669. result[1] = stmtList
  670. var loopBody = transformLoopBody(c, n[^1])
  671. discard c.breakSyms.pop
  672. let iter = call[0].sym
  673. var v = newNodeI(nkVarSection, n.info)
  674. for i in 0..<n.len - 2:
  675. if n[i].kind == nkVarTuple:
  676. for j in 0..<n[i].len-1:
  677. addVar(v, copyTree(n[i][j])) # declare new vars
  678. else:
  679. if n[i].kind == nkSym and isSimpleIteratorVar(c, iter, call, n[i].sym.owner):
  680. incl n[i].sym.flags, sfCursor
  681. addVar(v, copyTree(n[i])) # declare new vars
  682. stmtList.add(v)
  683. # Bugfix: inlined locals belong to the invoking routine, not to the invoked
  684. # iterator!
  685. var newC = newTransCon(getCurrOwner(c))
  686. newC.forStmt = n
  687. newC.forLoopBody = loopBody
  688. # this can fail for 'nimsuggest' and 'check':
  689. if iter.kind != skIterator: return result
  690. # generate access statements for the parameters (unless they are constant)
  691. pushTransCon(c, newC)
  692. for i in 1..<call.len:
  693. var arg = transform(c, call[i])
  694. let ff = skipTypes(iter.typ, abstractInst)
  695. # can happen for 'nim check':
  696. if i >= ff.n.len: return result
  697. var formal = ff.n[i].sym
  698. let pa = putArgInto(arg, formal.typ)
  699. case pa
  700. of paDirectMapping:
  701. idNodeTablePut(newC.mapping, formal, arg)
  702. of paFastAsgn, paFastAsgnTakeTypeFromArg:
  703. var t = formal.typ
  704. if pa == paFastAsgnTakeTypeFromArg:
  705. t = arg.typ
  706. elif formal.ast != nil and formal.ast.typ.destructor != nil and t.destructor == nil:
  707. t = formal.ast.typ # better use the type that actually has a destructor.
  708. elif t.destructor == nil and arg.typ.destructor != nil:
  709. t = arg.typ
  710. # generate a temporary and produce an assignment statement:
  711. var temp = newTemp(c, t, formal.info)
  712. addVar(v, temp)
  713. stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))
  714. idNodeTablePut(newC.mapping, formal, temp)
  715. of paVarAsgn:
  716. assert(skipTypes(formal.typ, abstractInst).kind in {tyVar})
  717. idNodeTablePut(newC.mapping, formal, arg)
  718. # XXX BUG still not correct if the arg has a side effect!
  719. of paComplexOpenarray:
  720. # arrays will deep copy here (pretty bad).
  721. var temp = newTemp(c, arg.typ, formal.info)
  722. addVar(v, temp)
  723. stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))
  724. idNodeTablePut(newC.mapping, formal, temp)
  725. let body = transformBody(c.graph, c.idgen, iter, useCache)
  726. pushInfoContext(c.graph.config, n.info)
  727. inc(c.inlining)
  728. stmtList.add(transform(c, body))
  729. #findWrongOwners(c, stmtList.PNode)
  730. dec(c.inlining)
  731. popInfoContext(c.graph.config)
  732. popTransCon(c)
  733. # echo "transformed: ", stmtList.renderTree
  734. proc transformCase(c: PTransf, n: PNode): PNode =
  735. # removes `elif` branches of a case stmt
  736. # adds ``else: nil`` if needed for the code generator
  737. result = newTransNode(nkCaseStmt, n, 0)
  738. var ifs: PNode = nil
  739. for it in n:
  740. var e = transform(c, it)
  741. case it.kind
  742. of nkElifBranch:
  743. if ifs == nil:
  744. # Generate the right node depending on whether `n` is used as a stmt or
  745. # as an expr
  746. let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
  747. ifs = newTransNode(kind, it.info, 0)
  748. ifs.typ = n.typ
  749. ifs.add(e)
  750. of nkElse:
  751. if ifs == nil: result.add(e)
  752. else: ifs.add(e)
  753. else:
  754. result.add(e)
  755. if ifs != nil:
  756. var elseBranch = newTransNode(nkElse, n.info, 1)
  757. elseBranch[0] = ifs
  758. result.add(elseBranch)
  759. elif result.lastSon.kind != nkElse and not (
  760. skipTypes(n[0].typ, abstractVarRange).kind in
  761. {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64}):
  762. # fix a stupid code gen bug by normalizing:
  763. var elseBranch = newTransNode(nkElse, n.info, 1)
  764. elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
  765. result.add(elseBranch)
  766. proc transformArrayAccess(c: PTransf, n: PNode): PNode =
  767. # XXX this is really bad; transf should use a proper AST visitor
  768. if n[0].kind == nkSym and n[0].sym.kind == skType:
  769. result = n
  770. else:
  771. result = transformSons(c, n)
  772. if n.len >= 2 and result[1].kind in {nkChckRange, nkChckRange64} and
  773. n[1].kind in {nkHiddenStdConv, nkHiddenSubConv}:
  774. # implicit conversion, was transformed into range check
  775. # remove in favor of index check if conversion to array index type
  776. # has to be done here because the array index type needs to be relaxed
  777. # i.e. a uint32 index can implicitly convert to range[0..3] but not int
  778. let arr = skipTypes(n[0].typ, abstractVarRange)
  779. if arr.kind == tyArray and
  780. firstOrd(c.graph.config, arr) == getOrdValue(result[1][1]) and
  781. lastOrd(c.graph.config, arr) == getOrdValue(result[1][2]):
  782. result[1] = result[1].skipConv
  783. proc getMergeOp(n: PNode): PSym =
  784. case n.kind
  785. of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
  786. nkCallStrLit:
  787. if n[0].kind == nkSym and n[0].sym.magic == mConStrStr:
  788. result = n[0].sym
  789. else: discard
  790. proc flattenTreeAux(d, a: PNode, op: PSym) =
  791. ## Optimizes away the `&` calls in the children nodes and
  792. ## lifts the leaf nodes to the same level as `op2`.
  793. let op2 = getMergeOp(a)
  794. if op2 != nil and
  795. (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
  796. for i in 1..<a.len: flattenTreeAux(d, a[i], op)
  797. else:
  798. d.add copyTree(a)
  799. proc flattenTree(root: PNode): PNode =
  800. let op = getMergeOp(root)
  801. if op != nil:
  802. result = copyNode(root)
  803. result.add copyTree(root[0])
  804. flattenTreeAux(result, root, op)
  805. else:
  806. result = root
  807. proc transformCall(c: PTransf, n: PNode): PNode =
  808. var n = flattenTree(n)
  809. let op = getMergeOp(n)
  810. let magic = getMagic(n)
  811. if op != nil and op.magic != mNone and n.len >= 3:
  812. result = newTransNode(nkCall, n, 0)
  813. result.add(transform(c, n[0]))
  814. var j = 1
  815. while j < n.len:
  816. var a = transform(c, n[j])
  817. inc(j)
  818. if isConstExpr(a):
  819. while (j < n.len):
  820. let b = transform(c, n[j])
  821. if not isConstExpr(b): break
  822. a = evalOp(op.magic, n, a, b, nil, c.idgen, c.graph)
  823. inc(j)
  824. result.add(a)
  825. if result.len == 2: result = result[1]
  826. elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
  827. # for bindSym(myconst) we MUST NOT perform constant folding:
  828. result = n
  829. elif magic == mProcCall:
  830. # but do not change to its dispatcher:
  831. result = transformSons(c, n[1])
  832. elif magic == mStrToStr:
  833. result = transform(c, n[1])
  834. else:
  835. let s = transformSons(c, n)
  836. # bugfix: check after 'transformSons' if it's still a method call:
  837. # use the dispatcher for the call:
  838. if s[0].kind == nkSym and s[0].sym.kind == skMethod:
  839. when false:
  840. let t = lastSon(s[0].sym.ast)
  841. if t.kind != nkSym or sfDispatcher notin t.sym.flags:
  842. methodDef(s[0].sym, false)
  843. result = methodCall(s, c.graph.config)
  844. else:
  845. result = s
  846. proc transformExceptBranch(c: PTransf, n: PNode): PNode =
  847. if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
  848. let excTypeNode = n[0][1]
  849. let actions = newTransNode(nkStmtListExpr, n[1], 2)
  850. # Generating `let exc = (excType)(getCurrentException())`
  851. # -> getCurrentException()
  852. let excCall = callCodegenProc(c.graph, "getCurrentException")
  853. # -> (excType)
  854. let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
  855. convNode[0] = newNodeI(nkEmpty, n.info)
  856. convNode[1] = excCall
  857. convNode.typ = excTypeNode.typ.toRef(c.idgen)
  858. # -> let exc = ...
  859. let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
  860. identDefs[0] = n[0][2]
  861. identDefs[1] = newNodeI(nkEmpty, n.info)
  862. identDefs[2] = convNode
  863. let letSection = newTransNode(nkLetSection, n[1].info, 1)
  864. letSection[0] = identDefs
  865. # Place the let statement and body of the 'except' branch into new stmtList.
  866. actions[0] = letSection
  867. actions[1] = transform(c, n[1])
  868. # Overwrite 'except' branch body with our stmtList.
  869. result = newTransNode(nkExceptBranch, n[1].info, 2)
  870. # Replace the `Exception as foobar` with just `Exception`.
  871. result[0] = transform(c, n[0][1])
  872. result[1] = actions
  873. else:
  874. result = transformSons(c, n)
  875. proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode): PNode =
  876. ## Merges adjacent constant expressions of the children of the `&` call into
  877. ## a single constant expression. It also inlines constant expressions which are not
  878. ## complex.
  879. result = n
  880. for i in 0..<n.safeLen:
  881. result[i] = commonOptimizations(g, idgen, c, n[i])
  882. var op = getMergeOp(n)
  883. if (op != nil) and (op.magic != mNone) and (n.len >= 3):
  884. result = newNodeIT(nkCall, n.info, n.typ)
  885. result.add(n[0])
  886. var args = newNode(nkArgList)
  887. flattenTreeAux(args, n, op)
  888. var j = 0
  889. while j < args.len:
  890. var a = args[j]
  891. inc(j)
  892. if isConstExpr(a):
  893. while j < args.len:
  894. let b = args[j]
  895. if not isConstExpr(b): break
  896. a = evalOp(op.magic, result, a, b, nil, idgen, g)
  897. inc(j)
  898. result.add(a)
  899. if result.len == 2: result = result[1]
  900. else:
  901. var cnst = getConstExpr(c, n, idgen, g)
  902. # we inline constants if they are not complex constants:
  903. if cnst != nil and not dontInlineConstant(n, cnst):
  904. result = cnst
  905. else:
  906. result = n
  907. proc transformDerefBlock(c: PTransf, n: PNode): PNode =
  908. # We transform (block: x)[] to (block: x[])
  909. let e0 = n[0]
  910. result = shallowCopy(e0)
  911. result.typ = n.typ
  912. for i in 0 ..< e0.len - 1:
  913. result[i] = e0[i]
  914. result[e0.len-1] = newTreeIT(nkHiddenDeref, n.info, n.typ, e0[e0.len-1])
  915. proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
  916. when false:
  917. var oldDeferAnchor: PNode
  918. if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
  919. nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
  920. nkBlockStmt, nkBlockExpr}:
  921. oldDeferAnchor = c.deferAnchor
  922. c.deferAnchor = n
  923. case n.kind
  924. of nkSym:
  925. result = transformSym(c, n)
  926. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
  927. # nothing to be done for leaves:
  928. result = n
  929. of nkBracketExpr: result = transformArrayAccess(c, n)
  930. of procDefs:
  931. var s = n[namePos].sym
  932. if n.typ != nil and s.typ.callConv == ccClosure:
  933. result = transformSym(c, n[namePos])
  934. # use the same node as before if still a symbol:
  935. if result.kind == nkSym: result = n
  936. else:
  937. result = n
  938. of nkMacroDef:
  939. # XXX no proper closure support yet:
  940. when false:
  941. if n[genericParamsPos].kind == nkEmpty:
  942. var s = n[namePos].sym
  943. n[bodyPos] = transform(c, s.getBody)
  944. if n.kind == nkMethodDef: methodDef(s, false)
  945. result = n
  946. of nkForStmt:
  947. result = transformFor(c, n)
  948. of nkParForStmt:
  949. result = transformSons(c, n)
  950. of nkCaseStmt:
  951. result = transformCase(c, n)
  952. of nkWhileStmt: result = transformWhile(c, n)
  953. of nkBlockStmt, nkBlockExpr:
  954. result = transformBlock(c, n)
  955. of nkDefer:
  956. c.deferDetected = true
  957. result = transformSons(c, n)
  958. when false:
  959. let deferPart = newNodeI(nkFinally, n.info)
  960. deferPart.add n[0]
  961. let tryStmt = newNodeI(nkTryStmt, n.info)
  962. if c.deferAnchor.isNil:
  963. tryStmt.add c.root
  964. c.root = tryStmt
  965. result = tryStmt
  966. else:
  967. # modify the corresponding *action*, don't rely on nkStmtList:
  968. tryStmt.add c.deferAnchor[^1]
  969. c.deferAnchor[^1] = tryStmt
  970. result = newTransNode(nkCommentStmt, n.info, 0)
  971. tryStmt.add deferPart
  972. # disable the original 'defer' statement:
  973. n.kind = nkEmpty
  974. of nkContinueStmt:
  975. result = newNodeI(nkBreakStmt, n.info)
  976. var labl = c.contSyms[c.contSyms.high]
  977. result.add(newSymNode(labl))
  978. of nkBreakStmt: result = transformBreak(c, n)
  979. of nkCallKinds:
  980. result = transformCall(c, n)
  981. of nkAddr, nkHiddenAddr:
  982. result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}, isAddr = true)
  983. of nkDerefExpr:
  984. result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
  985. of nkHiddenDeref:
  986. if n[0].kind in {nkBlockExpr, nkBlockStmt}:
  987. # bug #20107 bug #21540. Watch out to not deref the pointer too late.
  988. let e = transformDerefBlock(c, n)
  989. result = transformBlock(c, e)
  990. else:
  991. result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
  992. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  993. result = transformConv(c, n)
  994. of nkObjConstr, nkCast:
  995. # don't try to transform type node
  996. result = transformSonsAfterType(c, n)
  997. of nkDiscardStmt:
  998. result = n
  999. if n[0].kind != nkEmpty:
  1000. result = transformSons(c, n)
  1001. if isConstExpr(result[0]):
  1002. # ensure that e.g. discard "some comment" gets optimized away
  1003. # completely:
  1004. result = newNode(nkCommentStmt)
  1005. of nkCommentStmt, nkTemplateDef, nkImportStmt, nkStaticStmt,
  1006. nkExportStmt, nkExportExceptStmt:
  1007. return n
  1008. of nkConstSection:
  1009. # do not replace ``const c = 3`` with ``const 3 = 3``
  1010. return transformConstSection(c, n)
  1011. of nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt:
  1012. # no need to transform type sections:
  1013. return n
  1014. of nkVarSection, nkLetSection:
  1015. if c.inlining > 0:
  1016. # we need to copy the variables for multiple yield statements:
  1017. result = transformVarSection(c, n)
  1018. else:
  1019. result = transformSons(c, n)
  1020. of nkYieldStmt:
  1021. if c.inlining > 0 and not c.isIntroducingNewLocalVars:
  1022. result = transformYield(c, n)
  1023. else:
  1024. result = transformSons(c, n)
  1025. of nkAsgn:
  1026. result = transformAsgn(c, n)
  1027. of nkIdentDefs, nkConstDef:
  1028. result = newTransNode(n)
  1029. result[0] = transform(c, skipPragmaExpr(n[0]))
  1030. # Skip the second son since it only contains an unsemanticized copy of the
  1031. # variable type used by docgen
  1032. let last = n.len-1
  1033. for i in 1..<last: result[i] = n[i]
  1034. result[last] = transform(c, n[last])
  1035. # XXX comment handling really sucks:
  1036. if importantComments(c.graph.config):
  1037. result.comment = n.comment
  1038. of nkClosure:
  1039. # it can happen that for-loop-inlining produced a fresh
  1040. # set of variables, including some computed environment
  1041. # (bug #2604). We need to patch this environment here too:
  1042. let a = n[1]
  1043. if a.kind == nkSym:
  1044. result = copyTree(n)
  1045. result[1] = transformSymAux(c, a)
  1046. else:
  1047. result = n
  1048. of nkExceptBranch:
  1049. result = transformExceptBranch(c, n)
  1050. of nkCheckedFieldExpr:
  1051. result = transformSons(c, n)
  1052. if result[0].kind != nkDotExpr:
  1053. # simplfied beyond a dot expression --> simplify further.
  1054. result = result[0]
  1055. else:
  1056. result = transformSons(c, n)
  1057. when false:
  1058. if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
  1059. # Constants can be inlined here, but only if they cannot result in a cast
  1060. # in the back-end (e.g. var p: pointer = someProc)
  1061. let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
  1062. n.typ != nil and
  1063. n.typ.kind == tyPointer
  1064. if not exprIsPointerCast and not noConstFold:
  1065. var cnst = getConstExpr(c.module, result, c.idgen, c.graph)
  1066. # we inline constants if they are not complex constants:
  1067. if cnst != nil and not dontInlineConstant(n, cnst):
  1068. result = cnst # do not miss an optimization
  1069. proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
  1070. # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
  1071. # this step! We have to rely that the semantic pass transforms too errornous
  1072. # nodes into an empty node.
  1073. if nfTransf in n.flags: return n
  1074. pushTransCon(c, newTransCon(owner))
  1075. result = transform(c, n)
  1076. popTransCon(c)
  1077. incl(result.flags, nfTransf)
  1078. proc openTransf(g: ModuleGraph; module: PSym, filename: string; idgen: IdGenerator): PTransf =
  1079. new(result)
  1080. result.contSyms = @[]
  1081. result.breakSyms = @[]
  1082. result.module = module
  1083. result.graph = g
  1084. result.idgen = idgen
  1085. proc flattenStmts(n: PNode) =
  1086. var goOn = true
  1087. while goOn:
  1088. goOn = false
  1089. var i = 0
  1090. while i < n.len:
  1091. let it = n[i]
  1092. if it.kind in {nkStmtList, nkStmtListExpr}:
  1093. n.sons[i..i] = it.sons[0..<it.len]
  1094. goOn = true
  1095. inc i
  1096. proc liftDeferAux(n: PNode) =
  1097. if n.kind in {nkStmtList, nkStmtListExpr}:
  1098. flattenStmts(n)
  1099. var goOn = true
  1100. while goOn:
  1101. goOn = false
  1102. let last = n.len-1
  1103. for i in 0..last:
  1104. if n[i].kind == nkDefer:
  1105. let deferPart = newNodeI(nkFinally, n[i].info)
  1106. deferPart.add n[i][0]
  1107. var tryStmt = newNodeIT(nkTryStmt, n[i].info, n.typ)
  1108. var body = newNodeIT(n.kind, n[i].info, n.typ)
  1109. if i < last:
  1110. body.sons = n.sons[(i+1)..last]
  1111. tryStmt.add body
  1112. tryStmt.add deferPart
  1113. n[i] = tryStmt
  1114. n.sons.setLen(i+1)
  1115. n.typ = tryStmt.typ
  1116. goOn = true
  1117. break
  1118. for i in 0..n.safeLen-1:
  1119. liftDeferAux(n[i])
  1120. template liftDefer(c, root) =
  1121. if c.deferDetected:
  1122. liftDeferAux(root)
  1123. proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: TransformBodyFlag, force = false): PNode =
  1124. assert prc.kind in routineKinds
  1125. if prc.transformedBody != nil:
  1126. result = prc.transformedBody
  1127. elif nfTransf in getBody(g, prc).flags or prc.kind in {skTemplate}:
  1128. result = getBody(g, prc)
  1129. else:
  1130. prc.transformedBody = newNode(nkEmpty) # protects from recursion
  1131. var c = openTransf(g, prc.getModule, "", idgen)
  1132. result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, force)
  1133. result = processTransf(c, result, prc)
  1134. liftDefer(c, result)
  1135. result = liftLocalsIfRequested(prc, result, g.cache, g.config, c.idgen)
  1136. if prc.isIterator:
  1137. result = g.transformClosureIterator(c.idgen, prc, result)
  1138. incl(result.flags, nfTransf)
  1139. if flag == useCache or prc.typ.callConv == ccInline:
  1140. # genProc for inline procs will be called multiple times from different modules,
  1141. # it is important to transform exactly once to get sym ids and locations right
  1142. prc.transformedBody = result
  1143. else:
  1144. prc.transformedBody = nil
  1145. # XXX Rodfile support for transformedBody!
  1146. #if prc.name.s == "main":
  1147. # echo "transformed into ", renderTree(result, {renderIds})
  1148. proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode =
  1149. if nfTransf in n.flags:
  1150. result = n
  1151. else:
  1152. var c = openTransf(g, module, "", idgen)
  1153. result = processTransf(c, n, module)
  1154. liftDefer(c, result)
  1155. #result = liftLambdasForTopLevel(module, result)
  1156. incl(result.flags, nfTransf)
  1157. proc transformExpr*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode =
  1158. if nfTransf in n.flags:
  1159. result = n
  1160. else:
  1161. var c = openTransf(g, module, "", idgen)
  1162. result = processTransf(c, n, module)
  1163. liftDefer(c, result)
  1164. # expressions are not to be injected with destructor calls as that
  1165. # the list of top level statements needs to be collected before.
  1166. incl(result.flags, nfTransf)