transf.nim 45 KB

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