mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 22:10:33 +00:00
Change the order of compilation passes, transformation is made lazy at code gen (#8489)
* Ast no transformation * Add getImplNoTransform to the macros module * progress on delaying transf * Fix methods tranformation * Fix lazy lambdalifting * fix create thread wrapper * transform for lambda lifting * improve getImplTransformed * Fix destructor tests * try to fix nimprof for linux
This commit is contained in:
@@ -660,7 +660,7 @@ type
|
||||
mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo,
|
||||
mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
|
||||
mException, mBuiltinType, mSymOwner, mUncheckedArray
|
||||
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
@@ -811,7 +811,7 @@ type
|
||||
of routineKinds:
|
||||
procInstCache*: seq[PInstantiation]
|
||||
gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
|
||||
#scope*: PScope # the scope where the proc was defined
|
||||
transformedBody*: PNode # cached body after transf pass
|
||||
of skModule, skPackage:
|
||||
# modules keep track of the generic symbols they use from other modules.
|
||||
# this is because in incremental compilation, when a module is about to
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
||||
lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils
|
||||
lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf
|
||||
|
||||
import strutils except `%` # collides with ropes.`%`
|
||||
|
||||
@@ -845,6 +845,8 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
var header = genProcHeader(m, prc)
|
||||
var returnStmt: Rope = nil
|
||||
assert(prc.ast != nil)
|
||||
let procBody = transformBody(m.g.graph, prc, cache = false)
|
||||
|
||||
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
@@ -852,7 +854,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(m.config, prc.typ.sons[0]):
|
||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil):
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
var a: TLoc
|
||||
initLocExprSingleUse(p, val, a)
|
||||
@@ -873,7 +875,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
# global is either 'nil' or points to valid memory and so the RC operation
|
||||
# succeeds without touching not-initialized memory.
|
||||
if sfNoInit in prc.flags: discard
|
||||
elif allPathsAsgnResult(prc.getBody) == InitSkippable: discard
|
||||
elif allPathsAsgnResult(procBody) == InitSkippable: discard
|
||||
else:
|
||||
resetLoc(p, res.loc)
|
||||
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
||||
@@ -885,7 +887,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
if param.typ.isCompileTimeOnly: continue
|
||||
assignParam(p, param)
|
||||
closureSetup(p, prc)
|
||||
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: Rope
|
||||
if sfNoReturn in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
@@ -1522,7 +1524,8 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
m.initProc.options = initProcOptions(m)
|
||||
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||
# XXX replicate this logic!
|
||||
genStmts(m.initProc, n)
|
||||
let tranformed_n = transformStmt(m.g.graph, m.module, n)
|
||||
genStmts(m.initProc, tranformed_n)
|
||||
|
||||
proc finishModule(m: BModule) =
|
||||
var i = 0
|
||||
|
||||
@@ -281,6 +281,7 @@ proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym
|
||||
else:
|
||||
disp = ret
|
||||
nilchecks.add disp
|
||||
nilchecks.flags.incl nfTransf # should not be further transformed
|
||||
result.ast.sons[bodyPos] = nilchecks
|
||||
|
||||
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
|
||||
@@ -70,7 +70,7 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
|
||||
n = n.sons[0]
|
||||
inc derefs
|
||||
of nkBracketExpr:
|
||||
if isConstExpr(n.sons[1]) or isLet(n.sons[1]):
|
||||
if isConstExpr(n.sons[1]) or isLet(n.sons[1]) or isConstExpr(n.sons[1].skipConv):
|
||||
n = n.sons[0]
|
||||
else: return
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
|
||||
@@ -32,7 +32,7 @@ import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils, pathutils
|
||||
intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils, pathutils, transf
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -2021,7 +2021,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
|
||||
p.nested: genStmt(p, prc.getBody)
|
||||
let transformed_body = transformBody(oldProc.module.graph, prc, cache = false)
|
||||
p.nested: genStmt(p, transformed_body)
|
||||
|
||||
var def: Rope
|
||||
if not prc.constraint.isNil:
|
||||
@@ -2271,7 +2272,8 @@ proc genModule(p: PProc, n: PNode) =
|
||||
add(p.body, frameCreate(p,
|
||||
makeJSString("module " & p.module.module.name.s),
|
||||
makeJSString(toFilename(p.config, p.module.module.info))))
|
||||
genStmt(p, n)
|
||||
let n_transformed = transformStmt(p.module.graph, p.module.module, n)
|
||||
genStmt(p, n_transformed)
|
||||
if optStackTrace in p.options:
|
||||
add(p.body, frameDestroy(p))
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
|
||||
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos
|
||||
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
|
||||
transf
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
@@ -257,7 +258,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
# add 'new' statement:
|
||||
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
|
||||
result.add makeClosure(g, iter, env, n.info)
|
||||
|
||||
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
let obj = envParam.typ.lastSon
|
||||
@@ -390,7 +391,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if innerProc:
|
||||
if s.isIterator: c.somethingToDo = true
|
||||
if not c.processed.containsOrIncl(s.id):
|
||||
detectCapturedVars(s.getBody, s, c)
|
||||
let body = transformBody(c.graph, s)
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
if ow == owner:
|
||||
if owner.isIterator:
|
||||
@@ -651,14 +653,17 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
# echo renderTree(s.getBody, {renderIds})
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
var body = liftCapturedVars(s.getBody, s, d, c)
|
||||
var body = transformBody(d.graph, s)
|
||||
body = liftCapturedVars(body, s, d, c)
|
||||
if c.envvars.getOrDefault(s.id).isNil:
|
||||
s.ast.sons[bodyPos] = body
|
||||
s.transformedBody = body
|
||||
else:
|
||||
s.ast.sons[bodyPos] = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
|
||||
s.transformedBody = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
|
||||
c.inContainer = oldInContainer
|
||||
|
||||
if s.typ.callConv == ccClosure:
|
||||
result = symToClosure(n, owner, d, c)
|
||||
|
||||
elif s.id in d.capturedVars:
|
||||
if s.owner != owner:
|
||||
result = accessViaEnvParam(d.graph, n, owner)
|
||||
|
||||
@@ -405,6 +405,8 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
|
||||
varSection, varInit, call, barrier, fv: PNode;
|
||||
spawnKind: TSpawnResult): PSym =
|
||||
var body = newNodeI(nkStmtList, f.info)
|
||||
body.flags.incl nfTransf # do not transform further
|
||||
|
||||
var threadLocalBarrier: PSym
|
||||
if barrier != nil:
|
||||
var varSection2 = newNodeI(nkVarSection, barrier.info)
|
||||
|
||||
@@ -583,7 +583,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
result = buildEchoStmt(c, result)
|
||||
if c.config.cmd == cmdIdeTools:
|
||||
appendToModule(c.module, result)
|
||||
result = transformStmt(c.graph, c.module, result)
|
||||
trackTopLevelStmt(c.graph, c.module, result)
|
||||
|
||||
proc recoverContext(c: PContext) =
|
||||
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
||||
|
||||
@@ -413,14 +413,15 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
|
||||
result = newStrNodeT("console", n, g)
|
||||
|
||||
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
|
||||
var err = false
|
||||
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
|
||||
err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
|
||||
else:
|
||||
err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
|
||||
if err:
|
||||
localError(g.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
if tfUncheckedArray notin n.typ.flags:
|
||||
var err = false
|
||||
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
|
||||
err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
|
||||
else:
|
||||
err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
|
||||
if err:
|
||||
localError(g.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
|
||||
proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||
let dstTyp = skipTypes(n.typ, abstractRange)
|
||||
|
||||
@@ -146,9 +146,8 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
||||
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
|
||||
freshGenSyms(b, result, orig, symMap)
|
||||
b = semProcBody(c, b)
|
||||
b = hloBody(c, b)
|
||||
n.sons[bodyPos] = transformBody(c.graph, c.module, b, result)
|
||||
#echo "code instantiated ", result.name.s
|
||||
result.ast[bodyPos] = hloBody(c, b)
|
||||
trackProc(c.graph, result, result.ast[bodyPos])
|
||||
excl(result.flags, sfForward)
|
||||
dec c.inGenericInst
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
wordrecg, strutils, options, guards, writetracking, lineinfos,
|
||||
wordrecg, strutils, options, guards, writetracking, lineinfos, semfold,
|
||||
modulegraphs
|
||||
|
||||
when defined(useDfa):
|
||||
@@ -48,6 +48,7 @@ type
|
||||
tags: PNode # list of tags
|
||||
bottom, inTryStmt: int
|
||||
owner: PSym
|
||||
owner_module: PSym
|
||||
init: seq[int] # list of initialized variables
|
||||
guards: TModel # nested guards
|
||||
locked: seq[PNode] # locked locations
|
||||
@@ -562,8 +563,10 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
|
||||
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
|
||||
var effectList = op.n.sons[0]
|
||||
let s = n.skipConv
|
||||
if s.kind == nkSym and s.sym.kind in routineKinds:
|
||||
var s = n.skipConv
|
||||
if s.kind == nkCast and s[1].typ.kind == tyProc:
|
||||
s = s[1]
|
||||
if s.kind == nkSym and s.sym.kind in routineKinds and isNoEffectList(effectList):
|
||||
propagateEffects(tracked, n, s.sym)
|
||||
elif isNoEffectList(effectList):
|
||||
if isForwardedProc(n):
|
||||
@@ -709,9 +712,13 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkCallKinds:
|
||||
if getConstExpr(tracked.owner_module, n, tracked.graph) != nil:
|
||||
return
|
||||
# p's effects are ours too:
|
||||
let a = n.sons[0]
|
||||
var a = n.sons[0]
|
||||
let op = a.typ
|
||||
if a.kind == nkCast and a[1].typ.kind == tyProc:
|
||||
a = a[1]
|
||||
# XXX: in rare situations, templates and macros will reach here after
|
||||
# calling getAst(templateOrMacro()). Currently, templates and macros
|
||||
# are indistinguishable from normal procs (both have tyProc type) and
|
||||
@@ -934,6 +941,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
|
||||
t.exc = effects.sons[exceptionEffects]
|
||||
t.tags = effects.sons[tagEffects]
|
||||
t.owner = s
|
||||
t.owner_module = s.getModule
|
||||
t.init = @[]
|
||||
t.guards.s = @[]
|
||||
t.guards.o = initOperators(g)
|
||||
|
||||
@@ -1328,8 +1328,8 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
pushProcCon(c, s)
|
||||
addResult(c, s.typ.sons[0], n.info, skProc)
|
||||
addResultNode(c, n)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
|
||||
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
trackProc(c.graph, s, s.ast[bodyPos])
|
||||
popProcCon(c)
|
||||
elif efOperand notin flags:
|
||||
localError(c.config, n.info, errGenericLambdaNotAllowed)
|
||||
@@ -1369,8 +1369,8 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
pushProcCon(c, s)
|
||||
addResult(c, n.typ.sons[0], n.info, skProc)
|
||||
addResultNode(c, n)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
|
||||
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
trackProc(c.graph, s, s.ast[bodyPos])
|
||||
popProcCon(c)
|
||||
popOwner(c)
|
||||
closeScope(c)
|
||||
@@ -1683,10 +1683,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
|
||||
if lfDynamicLib notin s.loc.flags:
|
||||
# no semantic checking for importc:
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||
# context as it may even be evaluated in 'system.compiles':
|
||||
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
|
||||
trackProc(c.graph, s, s.ast[bodyPos])
|
||||
else:
|
||||
if s.typ.sons[0] != nil and kind != skIterator:
|
||||
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
|
||||
|
||||
@@ -30,6 +30,11 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
|
||||
localError(conf, info, "type 'var var' is not allowed")
|
||||
elif computeSize(conf, t) == szIllegalRecursion:
|
||||
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
|
||||
|
||||
t = typ.skipTypes({tyGenericInst})
|
||||
if t.kind == tyArray and tfUncheckedArray in t.flags:
|
||||
t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked
|
||||
|
||||
when false:
|
||||
if t.kind == tyObject and t.sons[0] != nil:
|
||||
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
|
||||
|
||||
@@ -21,9 +21,13 @@
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
|
||||
idents, renderer, types, passes, semfold, magicsys, cgmeth,
|
||||
lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters,
|
||||
sempass2, lowerings, destroyer, liftlocals,
|
||||
modulegraphs, lineinfos
|
||||
|
||||
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
|
||||
|
||||
import closureiters, lambdalifting
|
||||
|
||||
type
|
||||
PTransNode* = distinct PNode
|
||||
|
||||
@@ -62,18 +66,25 @@ proc newTransNode(kind: TNodeKind, n: PNode,
|
||||
var x = newNodeIT(kind, n.info, n.typ)
|
||||
newSeq(x.sons, sons)
|
||||
x.typ = n.typ
|
||||
# x.flags = n.flags
|
||||
result = x.PTransNode
|
||||
|
||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
||||
proc len(a: PTransNode): int {.inline.} = sonsLen(a.PNode)
|
||||
|
||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||
var n = PNode(a)
|
||||
n.sons[i] = PNode(x)
|
||||
|
||||
proc `[]=`(a: PTransNode, i: BackwardsIndex, x: PTransNode) {.inline.} =
|
||||
`[]=`(a, a.len - i.int, x)
|
||||
|
||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||
var n = PNode(a)
|
||||
result = n.sons[i].PTransNode
|
||||
|
||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
||||
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
||||
proc `[]`(a: PTransNode, i: BackwardsIndex): PTransNode {.inline.} =
|
||||
`[]`(a, a.len - i.int)
|
||||
|
||||
proc newTransCon(owner: PSym): PTransCon =
|
||||
assert owner != nil
|
||||
@@ -118,6 +129,8 @@ proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PTransNode): PTrans
|
||||
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
let s = n.sym
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
if s.kind in routineKinds:
|
||||
discard transformBody(c.graph, s)
|
||||
if s.kind == skIterator:
|
||||
if c.tooEarly: return n
|
||||
else: return liftIterSym(c.graph, n, getCurrOwner(c))
|
||||
@@ -146,7 +159,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
return
|
||||
tc = tc.next
|
||||
result = b
|
||||
|
||||
|
||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
result = PTransNode(transformSymAux(c, n))
|
||||
|
||||
@@ -561,9 +574,10 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
c.breakSyms.add(labl)
|
||||
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||
call.sons[0].typ.callConv == ccClosure:
|
||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
|
||||
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
|
||||
result[1] = n.PTransNode
|
||||
result[1][^1] = transformLoopBody(c, n[^1])
|
||||
result[1][^2] = transform(c, n[^2])
|
||||
result[1] = lambdalifting.liftForLoop(c.graph, result[1].PNode, getCurrOwner(c)).PTransNode
|
||||
discard c.breakSyms.pop
|
||||
return result
|
||||
|
||||
@@ -617,7 +631,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
||||
idNodeTablePut(newC.mapping, formal, temp)
|
||||
|
||||
var body = iter.getBody.copyTree
|
||||
let body = transformBody(c.graph, iter).copyTree
|
||||
pushInfoContext(c.graph.config, n.info)
|
||||
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
||||
var symMap: TIdTable
|
||||
@@ -1040,27 +1054,36 @@ template liftDefer(c, root) =
|
||||
if c.deferDetected:
|
||||
liftDeferAux(root)
|
||||
|
||||
proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
|
||||
if nfTransf in n.flags or prc.kind in {skTemplate}:
|
||||
result = n
|
||||
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
|
||||
assert prc.kind in routineKinds
|
||||
|
||||
if prc.transformedBody != nil:
|
||||
result = prc.transformedBody
|
||||
elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
|
||||
result = prc.ast[bodyPos]
|
||||
else:
|
||||
var c = openTransf(g, module, "")
|
||||
result = liftLambdas(g, prc, n, c.tooEarly)
|
||||
#result = n
|
||||
|
||||
prc.transformedBody = newNode(nkEmpty) # protects from recursion
|
||||
var c = openTransf(g, prc.getModule, "")
|
||||
result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
|
||||
result = processTransf(c, result, prc)
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdas(prc, result)
|
||||
when useEffectSystem: trackProc(g, prc, result)
|
||||
result = liftLocalsIfRequested(prc, result, g.cache, g.config)
|
||||
if c.needsDestroyPass: #and newDestructors:
|
||||
result = injectDestructorCalls(g, prc, result)
|
||||
|
||||
if prc.isIterator:
|
||||
result = g.transformClosureIterator(prc, result)
|
||||
|
||||
|
||||
incl(result.flags, nfTransf)
|
||||
#if prc.name.s == "testbody":
|
||||
# echo renderTree(result)
|
||||
|
||||
let cache = cache or prc.typ.callConv == ccInline
|
||||
if cache:
|
||||
# genProc for inline procs will be called multiple times from diffrent modules,
|
||||
# it is important to transform exactly once to get sym ids and locations right
|
||||
prc.transformedBody = result
|
||||
else:
|
||||
prc.transformedBody = nil
|
||||
|
||||
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
@@ -1070,9 +1093,6 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdasForTopLevel(module, result)
|
||||
when useEffectSystem: trackTopLevelStmt(g, module, result)
|
||||
#if n.info ?? "temp.nim":
|
||||
# echo renderTree(result, {renderIds})
|
||||
if c.needsDestroyPass:
|
||||
result = injectDestructorCalls(g, module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
@@ -924,6 +924,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node.flags.incl nfIsRef
|
||||
else:
|
||||
stackTrace(c, tos, pc, "node is not a symbol")
|
||||
of opcGetImplTransf:
|
||||
decodeB(rkNode)
|
||||
let a = regs[rb].node
|
||||
if a.kind == nkSym:
|
||||
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
|
||||
else:
|
||||
let ast = a.sym.ast.shallowCopy
|
||||
for i in 0..<a.sym.ast.len:
|
||||
ast[i] = a.sym.ast[i]
|
||||
ast[bodyPos] = transformBody(c.graph, a.sym)
|
||||
ast.copyTree()
|
||||
of opcSymOwner:
|
||||
decodeB(rkNode)
|
||||
let a = regs[rb].node
|
||||
|
||||
@@ -107,6 +107,7 @@ type
|
||||
opcEqIdent,
|
||||
opcStrToIdent,
|
||||
opcGetImpl,
|
||||
opcGetImplTransf
|
||||
|
||||
opcEcho,
|
||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
import
|
||||
strutils, ast, astalgo, types, msgs, renderer, vmdef,
|
||||
trees, intsets, magicsys, options, lowerings, lineinfos
|
||||
trees, intsets, magicsys, options, lowerings, lineinfos, transf
|
||||
import platform
|
||||
from os import splitFile
|
||||
|
||||
@@ -1122,6 +1122,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
|
||||
of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
|
||||
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
|
||||
of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf)
|
||||
of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
|
||||
of mNChild: genBinaryABC(c, n, dest, opcNChild)
|
||||
of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
|
||||
@@ -2129,7 +2130,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||
s.ast.sons[miscPos] = x
|
||||
# thanks to the jmp we can add top level statements easily and also nest
|
||||
# procs easily:
|
||||
let body = s.getBody
|
||||
let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
|
||||
let procStart = c.xjmp(body, opcJmp, 0)
|
||||
var p = PProc(blocks: @[], sym: s)
|
||||
let oldPrc = c.prc
|
||||
|
||||
@@ -252,6 +252,10 @@ else: # bootstrapping substitute
|
||||
else:
|
||||
n.strValOld
|
||||
|
||||
when defined(nimSymImplTransform):
|
||||
proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.}
|
||||
## for a typed proc returns the AST after transformation pass
|
||||
|
||||
when defined(nimHasSymOwnerInMacro):
|
||||
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
||||
## accepts node of kind nnkSym and returns its owner's symbol.
|
||||
|
||||
@@ -118,13 +118,13 @@ when defined(memProfiler):
|
||||
var
|
||||
gTicker {.threadvar.}: int
|
||||
|
||||
proc requestedHook(): bool {.nimcall.} =
|
||||
proc requestedHook(): bool {.nimcall, locks: 0.} =
|
||||
if gTicker == 0:
|
||||
gTicker = SamplingInterval
|
||||
result = true
|
||||
dec gTicker
|
||||
|
||||
proc hook(st: StackTrace, size: int) {.nimcall.} =
|
||||
proc hook(st: StackTrace, size: int) {.nimcall, locks: 0.} =
|
||||
when defined(ignoreAllocationSize):
|
||||
hookAux(st, 1)
|
||||
else:
|
||||
@@ -136,7 +136,7 @@ else:
|
||||
gTicker: int # we use an additional counter to
|
||||
# avoid calling 'getTicks' too frequently
|
||||
|
||||
proc requestedHook(): bool {.nimcall.} =
|
||||
proc requestedHook(): bool {.nimcall, locks: 0.} =
|
||||
if interval == 0: result = true
|
||||
elif gTicker == 0:
|
||||
gTicker = 500
|
||||
@@ -145,7 +145,7 @@ else:
|
||||
else:
|
||||
dec gTicker
|
||||
|
||||
proc hook(st: StackTrace) {.nimcall.} =
|
||||
proc hook(st: StackTrace) {.nimcall locks: 0.} =
|
||||
#echo "profiling! ", interval
|
||||
if interval == 0:
|
||||
hookAux(st, 1)
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
discard """
|
||||
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
|
||||
cmd: "nim check --hint[Performance]:off $file"
|
||||
nimout: '''
|
||||
tprevent_assign2.nim(53, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
|
||||
tprevent_assign2.nim(55, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
|
||||
tprevent_assign2.nim(66, 29) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(68, 9)
|
||||
'''
|
||||
file: "tprevent_assign2.nim"
|
||||
line: 48
|
||||
"""
|
||||
|
||||
type
|
||||
@@ -56,13 +51,5 @@ proc preventThis() =
|
||||
else:
|
||||
discard
|
||||
|
||||
proc preventThis2() =
|
||||
var otherTree: Foo
|
||||
try:
|
||||
try:
|
||||
otherTree = createTree(44)
|
||||
echo otherTree
|
||||
finally:
|
||||
take2(createTree(34), otherTree)
|
||||
finally:
|
||||
echo otherTree
|
||||
allowThis()
|
||||
preventThis()
|
||||
|
||||
53
tests/destructor/tprevent_assign3.nim
Normal file
53
tests/destructor/tprevent_assign3.nim
Normal file
@@ -0,0 +1,53 @@
|
||||
discard """
|
||||
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
file: "tprevent_assign3.nim"
|
||||
line: 46
|
||||
"""
|
||||
|
||||
type
|
||||
Foo = object
|
||||
x: int
|
||||
|
||||
proc `=destroy`(f: var Foo) = f.x = 0
|
||||
proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
|
||||
proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
|
||||
|
||||
proc createTree(x: int): Foo =
|
||||
Foo(x: x)
|
||||
|
||||
proc take2(a, b: sink Foo) =
|
||||
echo a.x, " ", b.x
|
||||
|
||||
proc allowThis() =
|
||||
var otherTree: Foo
|
||||
try:
|
||||
for i in 0..3:
|
||||
while true:
|
||||
#if i == 0:
|
||||
otherTree = createTree(44)
|
||||
case i
|
||||
of 0:
|
||||
echo otherTree
|
||||
take2(createTree(34), otherTree)
|
||||
of 1:
|
||||
take2(createTree(34), otherTree)
|
||||
else:
|
||||
discard
|
||||
finally:
|
||||
discard
|
||||
|
||||
proc preventThis2() =
|
||||
var otherTree: Foo
|
||||
try:
|
||||
try:
|
||||
otherTree = createTree(44)
|
||||
echo otherTree
|
||||
finally:
|
||||
take2(createTree(34), otherTree)
|
||||
finally:
|
||||
echo otherTree
|
||||
|
||||
allowThis()
|
||||
preventThis2()
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ proc fn3(x, y: int): bool =
|
||||
|
||||
static:
|
||||
let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n"
|
||||
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2.0 * x) / (x - y)\n"
|
||||
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2 * x) / (x - y)\n"
|
||||
let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
|
||||
doAssert fn1.repr_to_string == fn1s
|
||||
doAssert fn2.repr_to_string == fn2s
|
||||
|
||||
Reference in New Issue
Block a user