Skip to content

Commit

Permalink
allow generic compileTime proc folding (#22022)
Browse files Browse the repository at this point in the history
fixes #10753, fixes #22021, refs #19365 (was fixed by #22029, but more
faithful test added)

For whatever reason `compileTime` proc calls did not fold if the proc
was generic ([since this folding was
introduced](c25ffbf#diff-539da3a63df08fa987f1b0c67d26cdc690753843d110b6bf0805a685eeaffd40)).
I'm guessing the intention was for *unresolved* generic procs to not
fold, which is now the logic.

Non-magic `compileTime` procs also now don't fold at compile time in
`typeof` contexts to avoid possible runtime errors (only the important)
and prevent double/needless evaluation.
  • Loading branch information
metagn authored Aug 17, 2024
1 parent a354b18 commit f7c11a8
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 2 deletions.
1 change: 1 addition & 0 deletions compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ type
inUncheckedAssignSection*: int
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
inTypeofContext*: int
TBorrowState* = enum
bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch

Expand Down
6 changes: 4 additions & 2 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,8 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =

if callee.magic notin ctfeWhitelist: return

if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine:
if callee.kind notin {skProc, skFunc, skConverter, skConst} or
callee.isGenericRoutineStrict:
return

if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return
Expand Down Expand Up @@ -1118,7 +1119,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
not (result.typ.kind == tySequence and result.elementType.kind == tyEmpty):
liftTypeBoundOps(c, result.typ, n.info)
#result = patchResolvedTypeBoundOp(c, result)
if c.matchedConcept == nil:
if c.matchedConcept == nil and (c.inTypeofContext == 0 or callee.magic != mNone):
# don't fold calls in concepts and typeof
result = evalAtCompileTime(c, result)

proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
Expand Down
2 changes: 2 additions & 0 deletions compiler/semmagic.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
else:
m = mode.intVal
result = newNodeI(nkTypeOfExpr, n.info)
inc c.inTypeofContext
let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
dec c.inTypeofContext
result.add typExpr
result.typ = makeTypeDesc(c, typExpr.typ)

Expand Down
4 changes: 4 additions & 0 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1841,7 +1841,9 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =

proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
inc c.inTypeofContext
let t = semExprWithType(c, n, {efInTypeof})
dec c.inTypeofContext
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ
Expand All @@ -1855,7 +1857,9 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
else:
m = mode.intVal
inc c.inTypeofContext
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
dec c.inTypeofContext
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ
Expand Down
29 changes: 29 additions & 0 deletions tests/vm/tgenericcompiletimeproc.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
block: # issue #10753
proc foo(x: int): int {.compileTime.} = x
const a = foo(123)
doAssert foo(123) == a

proc bar[T](x: T): T {.compileTime.} = x
const b = bar(123)
doAssert bar(123) == b
const c = bar("abc")
doAssert bar("abc") == c

block: # issue #22021
proc foo(x: static int): int {.compileTime.} = x + 1
doAssert foo(123) == 124

block: # issue #19365
proc f[T](x: static T): T {.compileTime.} = x + x
doAssert f(123) == 246
doAssert f(1.0) == 2.0

block:
# don't fold compile time procs in typeof
proc fail[T](x: T): T {.compileTime.} =
doAssert false
x
doAssert typeof(fail(123)) is typeof(123)
proc p(x: int): int = x

type Foo = typeof(p(fail(123)))

0 comments on commit f7c11a8

Please sign in to comment.