fixes #21306; fixes #20485; don't transform yields in the var section when introducing new local vars [backport: 1.6] (#21489)

* fixes #21306;  don't transform yields in the var section when introducing new local vars

* adds `inVarSection` so the var section in the var section is freshed

* use `isIntroducingNewLocalVars` to avoid yield transformations in var sections

* fixes comments
This commit is contained in:
ringabout
2023-03-10 21:19:31 +08:00
committed by GitHub
parent 0319824322
commit f2dad94902
2 changed files with 118 additions and 1 deletions

View File

@@ -50,6 +50,7 @@ type
module: PSym
transCon: PTransCon # top of a TransCon stack
inlining: int # > 0 if we are in inlining context (copy vars)
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly: bool
graph: ModuleGraph
@@ -450,7 +451,9 @@ proc transformYield(c: PTransf, n: PNode): PNode =
result.add(c.transCon.forLoopBody)
else:
# we need to introduce new local variables:
c.isIntroducingNewLocalVars = true # don't transform yields when introducing new local vars
result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
c.isIntroducingNewLocalVars = false
for idx in 0 ..< result.len:
var changeNode = result[idx]
@@ -1036,7 +1039,7 @@ proc transform(c: PTransf, n: PNode): PNode =
else:
result = transformSons(c, n)
of nkYieldStmt:
if c.inlining > 0:
if c.inlining > 0 and not c.isIntroducingNewLocalVars:
result = transformYield(c, n)
else:
result = transformSons(c, n)

114
tests/iter/t21306.nim Normal file
View File

@@ -0,0 +1,114 @@
# bug #21306
type
FutureState {.pure.} = enum
Pending, Finished, Cancelled, Failed
FutureBase = ref object of RootObj
state: FutureState
error: ref CatchableError
id: uint
Future[T] = ref object of FutureBase
closure: iterator(f: Future[T]): FutureBase {.raises: [Defect, CatchableError, Exception], gcsafe.}
value: T
template setupFutureBase() =
new(result)
result.state = FutureState.Pending
proc newFutureImpl[T](): Future[T] =
setupFutureBase()
template newFuture[T](fromProc: static[string] = ""): Future[T] =
newFutureImpl[T]()
proc internalRead[T](fut: Future[T]): T =
when T isnot void:
return fut.value
template await[T](f: Future[T]): untyped =
when declared(chronosInternalRetFuture):
when not declaredInScope(chronosInternalTmpFuture):
var chronosInternalTmpFuture {.inject.}: FutureBase = f
else:
chronosInternalTmpFuture = f
yield chronosInternalTmpFuture
when T isnot void:
cast[type(f)](chronosInternalTmpFuture).internalRead()
type
VerifierError {.pure.} = enum
Invalid
MissingParent
UnviableFork
Duplicate
ProcessingCallback = proc() {.gcsafe, raises: [Defect].}
BlockVerifier =
proc(signedBlock: int):
Future[VerifierError] {.gcsafe, raises: [Defect].}
SyncQueueKind {.pure.} = enum
Forward, Backward
SyncRequest[T] = object
kind: SyncQueueKind
index: uint64
slot: uint64
count: uint64
item: T
SyncResult[T] = object
request: SyncRequest[T]
data: seq[ref int]
SyncQueue[T] = ref object
kind: SyncQueueKind
readyQueue: seq[SyncResult[T]]
blockVerifier: BlockVerifier
iterator blocks[T](sq: SyncQueue[T],
sr: SyncResult[T]): ref int =
case sq.kind
of SyncQueueKind.Forward:
for i in countup(0, len(sr.data) - 1):
yield sr.data[i]
of SyncQueueKind.Backward:
for i in countdown(len(sr.data) - 1, 0):
yield sr.data[i]
proc push[T](sq: SyncQueue[T]; sr: SyncRequest[T]; data: seq[ref int];
processingCb: ProcessingCallback = nil): Future[void] {.
stackTrace: off, gcsafe.} =
iterator push_436208182(chronosInternalRetFuture: Future[void]): FutureBase {.
closure, gcsafe, raises: [Defect, CatchableError, Exception].} =
block:
template result(): auto {.used.} =
{.fatal: "You should not reference the `result` variable inside" &
" a void async proc".}
let item = default(SyncResult[T])
for blk in sq.blocks(item):
let res = await sq.blockVerifier(blk[])
var resultFuture = newFuture[void]("push")
resultFuture.closure = push_436208182
return resultFuture
type
SomeTPeer = ref object
score: int
proc getSlice(): seq[ref int] =
discard
template smokeTest(kkind: SyncQueueKind, start, finish: uint64,
chunkSize: uint64) =
var queue: SyncQueue[SomeTPeer]
var request: SyncRequest[SomeTPeer]
discard queue.push(request, getSlice())
for k in {SyncQueueKind.Forward}:
for item in [(uint64(1181), uint64(1399), 41'u64)]:
smokeTest(k, item[0], item[1], item[2])