transf.nim 41 KB

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