diff --git a/changelog.md b/changelog.md index bf83a79fa5..6007a2d466 100644 --- a/changelog.md +++ b/changelog.md @@ -134,3 +134,5 @@ This now needs to be written as: own random number generators that do not require locking. - The compiler is now more consistent in its treatment of ambiguous symbols: Types that shadow procs and vice versa are marked as ambiguous (bug #6693). +- ``yield`` (or ``await`` which is mapped to ``yield``) never worked reliably + in an array, seq or object constructor and is now prevented at compile-time. diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index f8d107c84d..8204395242 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -455,6 +455,7 @@ type LiftingPass = object processed: IntSet envVars: Table[int, PNode] + inContainer: int proc initLiftingPass(fn: PSym): LiftingPass = result.processed = initIntSet() @@ -597,6 +598,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; proc transformYield(n: PNode; owner: PSym; d: DetectionPass; c: var LiftingPass): PNode = + if c.inContainer > 0: + localError(n.info, "invalid control flow: 'yield' within a constructor") let state = getStateField(owner) assert state != nil assert state.typ != nil @@ -703,11 +706,14 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; if not c.processed.containsOrIncl(s.id): #if s.name.s == "temp": # echo renderTree(s.getBody, {renderIds}) + let oldInContainer = c.inContainer + c.inContainer = 0 let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s) if c.envvars.getOrDefault(s.id).isNil: s.ast.sons[bodyPos] = body else: s.ast.sons[bodyPos] = newTree(nkStmtList, rawClosureCreation(s, d, c), body) + c.inContainer = oldInContainer if s.typ.callConv == ccClosure: result = symToClosure(n, owner, d, c) elif s.id in d.capturedVars: @@ -733,9 +739,12 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; n.sons[1] = x.sons[1] of nkLambdaKinds, nkIteratorDef, nkFuncDef: if n.typ != nil and n[namePos].kind == nkSym: + let oldInContainer = c.inContainer + c.inContainer = 0 let m = newSymNode(n[namePos].sym) m.typ = n.typ result = liftCapturedVars(m, owner, d, c) + c.inContainer = oldInContainer of nkHiddenStdConv: if n.len == 2: n.sons[1] = liftCapturedVars(n[1], owner, d, c) @@ -750,8 +759,12 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; # special case 'when nimVm' due to bug #3636: n.sons[1] = liftCapturedVars(n[1], owner, d, c) return + + let inContainer = n.kind in {nkObjConstr, nkBracket} + if inContainer: inc c.inContainer for i in 0..