Check there are no side effects before optimizing away compile time expressions. (#9934)

This commit is contained in:
deech
2018-12-31 07:41:24 -06:00
committed by Andreas Rumpf
parent bcbe317d17
commit e87910197a
3 changed files with 56 additions and 8 deletions

View File

@@ -710,16 +710,20 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
let a = getConstExpr(c.module, n.sons[i], c.graph)
if a == nil: return n
call.add(a)
#echo "NOW evaluating at compile time: ", call.renderTree
if sfCompileTime in callee.flags:
result = evalStaticExpr(c.module, c.graph, call, c.p.owner)
if result.isNil:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call))
else: result = fixupTypeAfterEval(c, result, n)
if c.inStaticContext == 0 or sfNoSideEffect in callee.flags:
if sfCompileTime in callee.flags:
result = evalStaticExpr(c.module, c.graph, call, c.p.owner)
if result.isNil:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call))
else: result = fixupTypeAfterEval(c, result, n)
else:
result = evalConstExpr(c.module, c.graph, call)
if result.isNil: result = n
else: result = fixupTypeAfterEval(c, result, n)
else:
result = evalConstExpr(c.module, c.graph, call)
if result.isNil: result = n
else: result = fixupTypeAfterEval(c, result, n)
result = n
#if result != n:
# echo "SUCCESS evaluated at compile time: ", call.renderTree

View File

@@ -548,6 +548,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
proc semConst(c: PContext, n: PNode): PNode =
result = copyNode(n)
inc c.inStaticContext
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
@@ -607,6 +608,7 @@ proc semConst(c: PContext, n: PNode): PNode =
v.ast = def[j]
b.sons[j] = newSymNode(v)
addSon(result,b)
dec c.inStaticContext
include semfields

View File

@@ -0,0 +1,42 @@
discard """
output:
'''
@[0, 1, 2]
@[3, 4, 5]
@[0, 1, 2]
3
4
'''
"""
template runNTimes(n: int, f : untyped) : untyped =
var accum: seq[type(f)]
for i in 0..n-1:
accum.add(f)
accum
var state {.compileTime.} : int = 0
proc fill(): int {.compileTime.} =
result = state
inc state
# invoke fill() at compile time as a compile time expression
const C1 = runNTimes(3, fill())
echo C1
# invoke fill() at compile time as a set of compile time statements
const C2 =
block:
runNTimes(3, fill())
echo C2
# invoke fill() at compile time after a compile time reset of state
const C3 =
block:
state = 0
runNTimes(3, fill())
echo C3
# evaluate fill() at compile time and use the results at runtime
echo fill()
echo fill()