transf.nim 44 KB

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