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:
parent
15dbd973de
commit
eaca5be9d6
22 changed files with 188 additions and 85 deletions
|
|
@ -660,7 +660,7 @@ type
|
||||||
mNHint, mNWarning, mNError,
|
mNHint, mNWarning, mNError,
|
||||||
mInstantiationInfo, mGetTypeInfo,
|
mInstantiationInfo, mGetTypeInfo,
|
||||||
mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
|
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:
|
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||||
const
|
const
|
||||||
|
|
@ -811,7 +811,7 @@ type
|
||||||
of routineKinds:
|
of routineKinds:
|
||||||
procInstCache*: seq[PInstantiation]
|
procInstCache*: seq[PInstantiation]
|
||||||
gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
|
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:
|
of skModule, skPackage:
|
||||||
# modules keep track of the generic symbols they use from other modules.
|
# modules keep track of the generic symbols they use from other modules.
|
||||||
# this is because in incremental compilation, when a module is about to
|
# 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,
|
nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
|
||||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
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.`%`
|
import strutils except `%` # collides with ropes.`%`
|
||||||
|
|
||||||
|
|
@ -845,6 +845,8 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
var header = genProcHeader(m, prc)
|
var header = genProcHeader(m, prc)
|
||||||
var returnStmt: Rope = nil
|
var returnStmt: Rope = nil
|
||||||
assert(prc.ast != 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 sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||||
if resultPos >= prc.ast.len:
|
if resultPos >= prc.ast.len:
|
||||||
internalError(m.config, prc.info, "proc has no result symbol")
|
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
|
let res = resNode.sym # get result symbol
|
||||||
if not isInvalidReturnType(m.config, prc.typ.sons[0]):
|
if not isInvalidReturnType(m.config, prc.typ.sons[0]):
|
||||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
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 decl = localVarDecl(p, resNode)
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExprSingleUse(p, val, a)
|
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
|
# global is either 'nil' or points to valid memory and so the RC operation
|
||||||
# succeeds without touching not-initialized memory.
|
# succeeds without touching not-initialized memory.
|
||||||
if sfNoInit in prc.flags: discard
|
if sfNoInit in prc.flags: discard
|
||||||
elif allPathsAsgnResult(prc.getBody) == InitSkippable: discard
|
elif allPathsAsgnResult(procBody) == InitSkippable: discard
|
||||||
else:
|
else:
|
||||||
resetLoc(p, res.loc)
|
resetLoc(p, res.loc)
|
||||||
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
||||||
|
|
@ -885,7 +887,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
if param.typ.isCompileTimeOnly: continue
|
if param.typ.isCompileTimeOnly: continue
|
||||||
assignParam(p, param)
|
assignParam(p, param)
|
||||||
closureSetup(p, prc)
|
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
|
var generatedProc: Rope
|
||||||
if sfNoReturn in prc.flags:
|
if sfNoReturn in prc.flags:
|
||||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
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)
|
m.initProc.options = initProcOptions(m)
|
||||||
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||||
# XXX replicate this logic!
|
# 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) =
|
proc finishModule(m: BModule) =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,7 @@ proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym
|
||||||
else:
|
else:
|
||||||
disp = ret
|
disp = ret
|
||||||
nilchecks.add disp
|
nilchecks.add disp
|
||||||
|
nilchecks.flags.incl nfTransf # should not be further transformed
|
||||||
result.ast.sons[bodyPos] = nilchecks
|
result.ast.sons[bodyPos] = nilchecks
|
||||||
|
|
||||||
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
|
||||||
n = n.sons[0]
|
n = n.sons[0]
|
||||||
inc derefs
|
inc derefs
|
||||||
of nkBracketExpr:
|
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]
|
n = n.sons[0]
|
||||||
else: return
|
else: return
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import
|
||||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
|
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
|
||||||
times, ropes, math, passes, ccgutils, wordrecg, renderer,
|
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
|
from modulegraphs import ModuleGraph, PPassContext
|
||||||
|
|
||||||
|
|
@ -2021,7 +2021,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
else:
|
else:
|
||||||
returnStmt = "return $#;$n" % [a.res]
|
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
|
var def: Rope
|
||||||
if not prc.constraint.isNil:
|
if not prc.constraint.isNil:
|
||||||
|
|
@ -2271,7 +2272,8 @@ proc genModule(p: PProc, n: PNode) =
|
||||||
add(p.body, frameCreate(p,
|
add(p.body, frameCreate(p,
|
||||||
makeJSString("module " & p.module.module.name.s),
|
makeJSString("module " & p.module.module.name.s),
|
||||||
makeJSString(toFilename(p.config, p.module.module.info))))
|
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:
|
if optStackTrace in p.options:
|
||||||
add(p.body, frameDestroy(p))
|
add(p.body, frameDestroy(p))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
|
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 """
|
discard """
|
||||||
The basic approach is that captured vars need to be put on the heap and
|
The basic approach is that captured vars need to be put on the heap and
|
||||||
|
|
@ -390,7 +391,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||||
if innerProc:
|
if innerProc:
|
||||||
if s.isIterator: c.somethingToDo = true
|
if s.isIterator: c.somethingToDo = true
|
||||||
if not c.processed.containsOrIncl(s.id):
|
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
|
let ow = s.skipGenericOwner
|
||||||
if ow == owner:
|
if ow == owner:
|
||||||
if owner.isIterator:
|
if owner.isIterator:
|
||||||
|
|
@ -651,14 +653,17 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||||
# echo renderTree(s.getBody, {renderIds})
|
# echo renderTree(s.getBody, {renderIds})
|
||||||
let oldInContainer = c.inContainer
|
let oldInContainer = c.inContainer
|
||||||
c.inContainer = 0
|
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:
|
if c.envvars.getOrDefault(s.id).isNil:
|
||||||
s.ast.sons[bodyPos] = body
|
s.transformedBody = body
|
||||||
else:
|
else:
|
||||||
s.ast.sons[bodyPos] = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
|
s.transformedBody = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
|
||||||
c.inContainer = oldInContainer
|
c.inContainer = oldInContainer
|
||||||
|
|
||||||
if s.typ.callConv == ccClosure:
|
if s.typ.callConv == ccClosure:
|
||||||
result = symToClosure(n, owner, d, c)
|
result = symToClosure(n, owner, d, c)
|
||||||
|
|
||||||
elif s.id in d.capturedVars:
|
elif s.id in d.capturedVars:
|
||||||
if s.owner != owner:
|
if s.owner != owner:
|
||||||
result = accessViaEnvParam(d.graph, n, 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;
|
varSection, varInit, call, barrier, fv: PNode;
|
||||||
spawnKind: TSpawnResult): PSym =
|
spawnKind: TSpawnResult): PSym =
|
||||||
var body = newNodeI(nkStmtList, f.info)
|
var body = newNodeI(nkStmtList, f.info)
|
||||||
|
body.flags.incl nfTransf # do not transform further
|
||||||
|
|
||||||
var threadLocalBarrier: PSym
|
var threadLocalBarrier: PSym
|
||||||
if barrier != nil:
|
if barrier != nil:
|
||||||
var varSection2 = newNodeI(nkVarSection, barrier.info)
|
var varSection2 = newNodeI(nkVarSection, barrier.info)
|
||||||
|
|
|
||||||
|
|
@ -583,7 +583,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
result = buildEchoStmt(c, result)
|
result = buildEchoStmt(c, result)
|
||||||
if c.config.cmd == cmdIdeTools:
|
if c.config.cmd == cmdIdeTools:
|
||||||
appendToModule(c.module, result)
|
appendToModule(c.module, result)
|
||||||
result = transformStmt(c.graph, c.module, result)
|
trackTopLevelStmt(c.graph, c.module, result)
|
||||||
|
|
||||||
proc recoverContext(c: PContext) =
|
proc recoverContext(c: PContext) =
|
||||||
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
||||||
|
|
|
||||||
|
|
@ -413,6 +413,7 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
|
||||||
result = newStrNodeT("console", n, g)
|
result = newStrNodeT("console", n, g)
|
||||||
|
|
||||||
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
|
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
|
||||||
|
if tfUncheckedArray notin n.typ.flags:
|
||||||
var err = false
|
var err = false
|
||||||
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
|
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)
|
err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
|
||||||
freshGenSyms(b, result, orig, symMap)
|
freshGenSyms(b, result, orig, symMap)
|
||||||
b = semProcBody(c, b)
|
b = semProcBody(c, b)
|
||||||
b = hloBody(c, b)
|
result.ast[bodyPos] = hloBody(c, b)
|
||||||
n.sons[bodyPos] = transformBody(c.graph, c.module, b, result)
|
trackProc(c.graph, result, result.ast[bodyPos])
|
||||||
#echo "code instantiated ", result.name.s
|
|
||||||
excl(result.flags, sfForward)
|
excl(result.flags, sfForward)
|
||||||
dec c.inGenericInst
|
dec c.inGenericInst
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||||
wordrecg, strutils, options, guards, writetracking, lineinfos,
|
wordrecg, strutils, options, guards, writetracking, lineinfos, semfold,
|
||||||
modulegraphs
|
modulegraphs
|
||||||
|
|
||||||
when defined(useDfa):
|
when defined(useDfa):
|
||||||
|
|
@ -48,6 +48,7 @@ type
|
||||||
tags: PNode # list of tags
|
tags: PNode # list of tags
|
||||||
bottom, inTryStmt: int
|
bottom, inTryStmt: int
|
||||||
owner: PSym
|
owner: PSym
|
||||||
|
owner_module: PSym
|
||||||
init: seq[int] # list of initialized variables
|
init: seq[int] # list of initialized variables
|
||||||
guards: TModel # nested guards
|
guards: TModel # nested guards
|
||||||
locked: seq[PNode] # locked locations
|
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:
|
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
|
||||||
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
|
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
|
||||||
var effectList = op.n.sons[0]
|
var effectList = op.n.sons[0]
|
||||||
let s = n.skipConv
|
var s = n.skipConv
|
||||||
if s.kind == nkSym and s.sym.kind in routineKinds:
|
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)
|
propagateEffects(tracked, n, s.sym)
|
||||||
elif isNoEffectList(effectList):
|
elif isNoEffectList(effectList):
|
||||||
if isForwardedProc(n):
|
if isForwardedProc(n):
|
||||||
|
|
@ -709,9 +712,13 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
for i in 0 ..< safeLen(n):
|
for i in 0 ..< safeLen(n):
|
||||||
track(tracked, n.sons[i])
|
track(tracked, n.sons[i])
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
|
if getConstExpr(tracked.owner_module, n, tracked.graph) != nil:
|
||||||
|
return
|
||||||
# p's effects are ours too:
|
# p's effects are ours too:
|
||||||
let a = n.sons[0]
|
var a = n.sons[0]
|
||||||
let op = a.typ
|
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
|
# XXX: in rare situations, templates and macros will reach here after
|
||||||
# calling getAst(templateOrMacro()). Currently, templates and macros
|
# calling getAst(templateOrMacro()). Currently, templates and macros
|
||||||
# are indistinguishable from normal procs (both have tyProc type) and
|
# 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.exc = effects.sons[exceptionEffects]
|
||||||
t.tags = effects.sons[tagEffects]
|
t.tags = effects.sons[tagEffects]
|
||||||
t.owner = s
|
t.owner = s
|
||||||
|
t.owner_module = s.getModule
|
||||||
t.init = @[]
|
t.init = @[]
|
||||||
t.guards.s = @[]
|
t.guards.s = @[]
|
||||||
t.guards.o = initOperators(g)
|
t.guards.o = initOperators(g)
|
||||||
|
|
|
||||||
|
|
@ -1328,8 +1328,8 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
pushProcCon(c, s)
|
pushProcCon(c, s)
|
||||||
addResult(c, s.typ.sons[0], n.info, skProc)
|
addResult(c, s.typ.sons[0], n.info, skProc)
|
||||||
addResultNode(c, n)
|
addResultNode(c, n)
|
||||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||||
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
|
trackProc(c.graph, s, s.ast[bodyPos])
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
elif efOperand notin flags:
|
elif efOperand notin flags:
|
||||||
localError(c.config, n.info, errGenericLambdaNotAllowed)
|
localError(c.config, n.info, errGenericLambdaNotAllowed)
|
||||||
|
|
@ -1369,8 +1369,8 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||||
pushProcCon(c, s)
|
pushProcCon(c, s)
|
||||||
addResult(c, n.typ.sons[0], n.info, skProc)
|
addResult(c, n.typ.sons[0], n.info, skProc)
|
||||||
addResultNode(c, n)
|
addResultNode(c, n)
|
||||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||||
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
|
trackProc(c.graph, s, s.ast[bodyPos])
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
@ -1683,10 +1683,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
|
|
||||||
if lfDynamicLib notin s.loc.flags:
|
if lfDynamicLib notin s.loc.flags:
|
||||||
# no semantic checking for importc:
|
# 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'
|
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||||
# context as it may even be evaluated 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:
|
else:
|
||||||
if s.typ.sons[0] != nil and kind != skIterator:
|
if s.typ.sons[0] != nil and kind != skIterator:
|
||||||
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
|
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")
|
localError(conf, info, "type 'var var' is not allowed")
|
||||||
elif computeSize(conf, t) == szIllegalRecursion:
|
elif computeSize(conf, t) == szIllegalRecursion:
|
||||||
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
|
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:
|
when false:
|
||||||
if t.kind == tyObject and t.sons[0] != nil:
|
if t.kind == tyObject and t.sons[0] != nil:
|
||||||
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
|
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,13 @@
|
||||||
import
|
import
|
||||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
|
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
|
||||||
idents, renderer, types, passes, semfold, magicsys, cgmeth,
|
idents, renderer, types, passes, semfold, magicsys, cgmeth,
|
||||||
lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters,
|
sempass2, lowerings, destroyer, liftlocals,
|
||||||
modulegraphs, lineinfos
|
modulegraphs, lineinfos
|
||||||
|
|
||||||
|
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
|
||||||
|
|
||||||
|
import closureiters, lambdalifting
|
||||||
|
|
||||||
type
|
type
|
||||||
PTransNode* = distinct PNode
|
PTransNode* = distinct PNode
|
||||||
|
|
||||||
|
|
@ -62,18 +66,25 @@ proc newTransNode(kind: TNodeKind, n: PNode,
|
||||||
var x = newNodeIT(kind, n.info, n.typ)
|
var x = newNodeIT(kind, n.info, n.typ)
|
||||||
newSeq(x.sons, sons)
|
newSeq(x.sons, sons)
|
||||||
x.typ = n.typ
|
x.typ = n.typ
|
||||||
|
# x.flags = n.flags
|
||||||
result = x.PTransNode
|
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.} =
|
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||||
var n = PNode(a)
|
var n = PNode(a)
|
||||||
n.sons[i] = PNode(x)
|
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.} =
|
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||||
var n = PNode(a)
|
var n = PNode(a)
|
||||||
result = n.sons[i].PTransNode
|
result = n.sons[i].PTransNode
|
||||||
|
|
||||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
proc `[]`(a: PTransNode, i: BackwardsIndex): PTransNode {.inline.} =
|
||||||
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
`[]`(a, a.len - i.int)
|
||||||
|
|
||||||
proc newTransCon(owner: PSym): PTransCon =
|
proc newTransCon(owner: PSym): PTransCon =
|
||||||
assert owner != nil
|
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 =
|
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||||
|
if s.kind in routineKinds:
|
||||||
|
discard transformBody(c.graph, s)
|
||||||
if s.kind == skIterator:
|
if s.kind == skIterator:
|
||||||
if c.tooEarly: return n
|
if c.tooEarly: return n
|
||||||
else: return liftIterSym(c.graph, n, getCurrOwner(c))
|
else: return liftIterSym(c.graph, n, getCurrOwner(c))
|
||||||
|
|
@ -561,9 +574,10 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
c.breakSyms.add(labl)
|
c.breakSyms.add(labl)
|
||||||
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||||
call.sons[0].typ.callConv == ccClosure:
|
call.sons[0].typ.callConv == ccClosure:
|
||||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
result[1] = n.PTransNode
|
||||||
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
|
result[1][^1] = transformLoopBody(c, n[^1])
|
||||||
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
|
result[1][^2] = transform(c, n[^2])
|
||||||
|
result[1] = lambdalifting.liftForLoop(c.graph, result[1].PNode, getCurrOwner(c)).PTransNode
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -617,7 +631,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
||||||
idNodeTablePut(newC.mapping, formal, temp)
|
idNodeTablePut(newC.mapping, formal, temp)
|
||||||
|
|
||||||
var body = iter.getBody.copyTree
|
let body = transformBody(c.graph, iter).copyTree
|
||||||
pushInfoContext(c.graph.config, n.info)
|
pushInfoContext(c.graph.config, n.info)
|
||||||
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
||||||
var symMap: TIdTable
|
var symMap: TIdTable
|
||||||
|
|
@ -1040,17 +1054,20 @@ template liftDefer(c, root) =
|
||||||
if c.deferDetected:
|
if c.deferDetected:
|
||||||
liftDeferAux(root)
|
liftDeferAux(root)
|
||||||
|
|
||||||
proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
|
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
|
||||||
if nfTransf in n.flags or prc.kind in {skTemplate}:
|
assert prc.kind in routineKinds
|
||||||
result = n
|
|
||||||
|
if prc.transformedBody != nil:
|
||||||
|
result = prc.transformedBody
|
||||||
|
elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
|
||||||
|
result = prc.ast[bodyPos]
|
||||||
else:
|
else:
|
||||||
var c = openTransf(g, module, "")
|
|
||||||
result = liftLambdas(g, prc, n, c.tooEarly)
|
prc.transformedBody = newNode(nkEmpty) # protects from recursion
|
||||||
#result = n
|
var c = openTransf(g, prc.getModule, "")
|
||||||
|
result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
|
||||||
result = processTransf(c, result, prc)
|
result = processTransf(c, result, prc)
|
||||||
liftDefer(c, result)
|
liftDefer(c, result)
|
||||||
#result = liftLambdas(prc, result)
|
|
||||||
when useEffectSystem: trackProc(g, prc, result)
|
|
||||||
result = liftLocalsIfRequested(prc, result, g.cache, g.config)
|
result = liftLocalsIfRequested(prc, result, g.cache, g.config)
|
||||||
if c.needsDestroyPass: #and newDestructors:
|
if c.needsDestroyPass: #and newDestructors:
|
||||||
result = injectDestructorCalls(g, prc, result)
|
result = injectDestructorCalls(g, prc, result)
|
||||||
|
|
@ -1059,8 +1076,14 @@ proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
|
||||||
result = g.transformClosureIterator(prc, result)
|
result = g.transformClosureIterator(prc, result)
|
||||||
|
|
||||||
incl(result.flags, nfTransf)
|
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 =
|
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||||
if nfTransf in n.flags:
|
if nfTransf in n.flags:
|
||||||
|
|
@ -1070,9 +1093,6 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||||
result = processTransf(c, n, module)
|
result = processTransf(c, n, module)
|
||||||
liftDefer(c, result)
|
liftDefer(c, result)
|
||||||
#result = liftLambdasForTopLevel(module, result)
|
#result = liftLambdasForTopLevel(module, result)
|
||||||
when useEffectSystem: trackTopLevelStmt(g, module, result)
|
|
||||||
#if n.info ?? "temp.nim":
|
|
||||||
# echo renderTree(result, {renderIds})
|
|
||||||
if c.needsDestroyPass:
|
if c.needsDestroyPass:
|
||||||
result = injectDestructorCalls(g, module, result)
|
result = injectDestructorCalls(g, module, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
|
||||||
|
|
@ -924,6 +924,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
regs[ra].node.flags.incl nfIsRef
|
regs[ra].node.flags.incl nfIsRef
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, "node is not a symbol")
|
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:
|
of opcSymOwner:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
let a = regs[rb].node
|
let a = regs[rb].node
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ type
|
||||||
opcEqIdent,
|
opcEqIdent,
|
||||||
opcStrToIdent,
|
opcStrToIdent,
|
||||||
opcGetImpl,
|
opcGetImpl,
|
||||||
|
opcGetImplTransf
|
||||||
|
|
||||||
opcEcho,
|
opcEcho,
|
||||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, ast, astalgo, types, msgs, renderer, vmdef,
|
strutils, ast, astalgo, types, msgs, renderer, vmdef,
|
||||||
trees, intsets, magicsys, options, lowerings, lineinfos
|
trees, intsets, magicsys, options, lowerings, lineinfos, transf
|
||||||
import platform
|
import platform
|
||||||
from os import splitFile
|
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 mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
|
||||||
of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
|
of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
|
||||||
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
|
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
|
||||||
|
of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf)
|
||||||
of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
|
of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
|
||||||
of mNChild: genBinaryABC(c, n, dest, opcNChild)
|
of mNChild: genBinaryABC(c, n, dest, opcNChild)
|
||||||
of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
|
of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
|
||||||
|
|
@ -2129,7 +2130,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
s.ast.sons[miscPos] = x
|
s.ast.sons[miscPos] = x
|
||||||
# thanks to the jmp we can add top level statements easily and also nest
|
# thanks to the jmp we can add top level statements easily and also nest
|
||||||
# procs easily:
|
# procs easily:
|
||||||
let body = s.getBody
|
let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
|
||||||
let procStart = c.xjmp(body, opcJmp, 0)
|
let procStart = c.xjmp(body, opcJmp, 0)
|
||||||
var p = PProc(blocks: @[], sym: s)
|
var p = PProc(blocks: @[], sym: s)
|
||||||
let oldPrc = c.prc
|
let oldPrc = c.prc
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,10 @@ else: # bootstrapping substitute
|
||||||
else:
|
else:
|
||||||
n.strValOld
|
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):
|
when defined(nimHasSymOwnerInMacro):
|
||||||
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
||||||
## accepts node of kind nnkSym and returns its owner's symbol.
|
## accepts node of kind nnkSym and returns its owner's symbol.
|
||||||
|
|
|
||||||
|
|
@ -118,13 +118,13 @@ when defined(memProfiler):
|
||||||
var
|
var
|
||||||
gTicker {.threadvar.}: int
|
gTicker {.threadvar.}: int
|
||||||
|
|
||||||
proc requestedHook(): bool {.nimcall.} =
|
proc requestedHook(): bool {.nimcall, locks: 0.} =
|
||||||
if gTicker == 0:
|
if gTicker == 0:
|
||||||
gTicker = SamplingInterval
|
gTicker = SamplingInterval
|
||||||
result = true
|
result = true
|
||||||
dec gTicker
|
dec gTicker
|
||||||
|
|
||||||
proc hook(st: StackTrace, size: int) {.nimcall.} =
|
proc hook(st: StackTrace, size: int) {.nimcall, locks: 0.} =
|
||||||
when defined(ignoreAllocationSize):
|
when defined(ignoreAllocationSize):
|
||||||
hookAux(st, 1)
|
hookAux(st, 1)
|
||||||
else:
|
else:
|
||||||
|
|
@ -136,7 +136,7 @@ else:
|
||||||
gTicker: int # we use an additional counter to
|
gTicker: int # we use an additional counter to
|
||||||
# avoid calling 'getTicks' too frequently
|
# avoid calling 'getTicks' too frequently
|
||||||
|
|
||||||
proc requestedHook(): bool {.nimcall.} =
|
proc requestedHook(): bool {.nimcall, locks: 0.} =
|
||||||
if interval == 0: result = true
|
if interval == 0: result = true
|
||||||
elif gTicker == 0:
|
elif gTicker == 0:
|
||||||
gTicker = 500
|
gTicker = 500
|
||||||
|
|
@ -145,7 +145,7 @@ else:
|
||||||
else:
|
else:
|
||||||
dec gTicker
|
dec gTicker
|
||||||
|
|
||||||
proc hook(st: StackTrace) {.nimcall.} =
|
proc hook(st: StackTrace) {.nimcall locks: 0.} =
|
||||||
#echo "profiling! ", interval
|
#echo "profiling! ", interval
|
||||||
if interval == 0:
|
if interval == 0:
|
||||||
hookAux(st, 1)
|
hookAux(st, 1)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||||
|
file: "tprevent_assign2.nim"
|
||||||
cmd: "nim check --hint[Performance]:off $file"
|
line: 48
|
||||||
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)
|
|
||||||
'''
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -56,13 +51,5 @@ proc preventThis() =
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc preventThis2() =
|
allowThis()
|
||||||
var otherTree: Foo
|
preventThis()
|
||||||
try:
|
|
||||||
try:
|
|
||||||
otherTree = createTree(44)
|
|
||||||
echo otherTree
|
|
||||||
finally:
|
|
||||||
take2(createTree(34), otherTree)
|
|
||||||
finally:
|
|
||||||
echo otherTree
|
|
||||||
|
|
|
||||||
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:
|
static:
|
||||||
let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n"
|
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"
|
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 fn1.repr_to_string == fn1s
|
||||||
doAssert fn2.repr_to_string == fn2s
|
doAssert fn2.repr_to_string == fn2s
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue