transf.nim 41 KB

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