Fix GH-23301: nested "yield from" repeats a value after "yield from []" - #23302
Fix GH-23301: nested "yield from" repeats a value after "yield from []"#23302lazerg wants to merge 1 commit into
Conversation
c2f8b57 to
622159a
Compare
LamentXU123
left a comment
There was a problem hiding this comment.
I'd say this is an extremely crafted case that basically don't happens read world. But code-wise, this looks good.
@arnaud-lb Could you please take a look at this?
|
@LamentXU123 no it's actually a widespread problem, twig doesn't work basically: #22640 (comment) |
iliaal
left a comment
There was a problem hiding this comment.
Fix looks right to me. node.parent is the correct discriminator: zend_generator_yield_from() sets it alongside DO_INIT and is only reached for a generator operand, so it separates a live delegation from the stale flag a middle generator keeps afterwards.
The scope is wider than the title suggests, though. Diffing against a pre-22640 build, current 8.4 also repeats the value for yield from new ArrayIterator([]) and for a non-empty array tail, triples it in a four-level chain, and yields a duplicate key: k0=A,k1=B,k0=B where 8.3 gives k0=A,k1=B. Every one of those matches the pre-22640 output again with this patch, and gh15375 including its shared-primed section still passes.
One thing for whoever merges it: merging into current PHP-8.4 auto-merges NEWS and silently drops the GH-23301 line, so it needs adding back by hand.
GH-15375's fix made the
DO_INITre-advance guard inzend_generator_resume()read the flag from the delegating generator rather than fromorig_generator. That flag is set byzend_generator_yield_from()and only ever cleared onorig_generator, so on a middle generator it stays set for the rest of its life.When such a middle generator then delegates to a non-generator iterable (
yield from []), it still sits on aZEND_YIELD_FROMopline, so it is picked as the delegator even though no new generator link was established, and its staleDO_INITsuppresses the resume. The value it yielded last is presented a second time. Twig hits this on every template, sincedoDisplay()always ends withyield from [];.Only treat the generator as the delegator when it actually delegated to another generator (
node.parentis set); otherwise keeporig_generatoras before. The GH-15375 tests still pass.Fixes GH-23301