diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 946a144321..59bddeae19 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -1307,16 +1307,15 @@ proc countStateOccurences(ctx: var Ctx, n: PNode, stateOccurences: var openArray proc replaceDeletedStates(ctx: var Ctx, n: PNode): PNode = result = n - for i in 0 ..< n.safeLen: - let c = n[i] - if c.kind == nkIntLit: - let idx = c.intVal - if idx >= 0 and idx < ctx.states.len and ctx.states[idx].label == c and ctx.states[idx].deletable: - let gt = ctx.replaceDeletedStates(skipStmtList(ctx.states[idx].body)) - assert(gt.kind == nkGotoState) - n[i] = gt[0] - else: - n[i] = ctx.replaceDeletedStates(c) + if n.kind == nkIntLit: + let idx = n.intVal + if idx >= 0 and idx < ctx.states.len and ctx.states[idx].label == n and ctx.states[idx].deletable: + let gt = ctx.replaceDeletedStates(skipStmtList(ctx.states[idx].body)) + assert(gt.kind == nkGotoState) + result = gt[0] + else: + for i in 0 ..< n.safeLen: + n[i] = ctx.replaceDeletedStates(n[i]) proc replaceInlinedStates(ctx: var Ctx, n: PNode): PNode = ## Find all nkGotoState(stateIdx) nodes that do not follow nkYield. @@ -1347,6 +1346,7 @@ proc optimizeStates(ctx: var Ctx) = # Replace deletable state labels to labels of respective non-empty states for i in 0 .. ctx.states.high: ctx.states[i].body = ctx.replaceDeletedStates(ctx.states[i].body) + ctx.states[i].excLandingState = ctx.replaceDeletedStates(ctx.states[i].excLandingState) # Remove deletable states var i = 0 diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 21e084ea1b..983cae5408 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -17,9 +17,12 @@ proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedRe var exceptionCaught = false + var maxIterations = 10000 try: for i in it(): closureIterResult.add(i) + dec maxIterations + doAssert(maxIterations > 0, "Too many iterations in test. Infinite loop?") except TestError: exceptionCaught = true @@ -847,3 +850,50 @@ block: doAssert(w() == 123) doAssert(getCurrentExceptionMsg() == "Outer error") doAssert(getCurrentExceptionMsg() == "") + +block: #25330 (v1) + iterator count1(): int {.closure.} = + yield 1 + raiseTestError() + + iterator count0(): int {.closure.} = + try: + var count = count1 + while true: + yield count() + if finished(count): break + finally: + try: + checkpoint(2) + var count2 = count1 + while true: + yield count2() + if finished(count2): break + discard # removing this outputs "raise" + except: + checkpoint(3) + raise + + testExc(count0, 1, 2, 1, 3) + +block: #25330 (v2) + iterator count1(): int {.closure.} = + yield 1 + raiseTestError() + + iterator count0(): int {.closure.} = + try: + var count = count1 + for x in 0 .. 10: + yield count() + finally: + try: + checkpoint(2) + var count2 = count1 + for x in 0 .. 10: + yield count2() + except: + checkpoint(3) + raise + + testExc(count0, 1, 2, 1, 3)