The DO_INIT flag, which will skip the first resume on a primed
generator, should always be set when starting to yield from a
new generator, not only when the yield from happens during priming.
This commit is contained in:
Nikita Popov 2020-04-03 10:06:41 +02:00
parent 1327491224
commit 823a956855
4 changed files with 34 additions and 5 deletions

3
NEWS
View File

@ -3,6 +3,9 @@ PHP NEWS
?? ??? ????, PHP 7.4.6
- Core:
. Fixed bug #78434 (Generator yields no items after valid() call). (Nikita)
- DOM:
. Fixed bug #78221 (DOMNode::normalize() doesn't remove empty text nodes).
(cmb)

View File

@ -0,0 +1,27 @@
--TEST--
Bug #78434: Generator skips first item after valid() call
--FILE--
<?php
$function = function () {
yield 0;
};
$wrapper = function () use ($function) {
$generator = $function();
$generator->valid();
yield from $generator;
$generator = $function();
$generator->valid();
yield from $generator;
};
foreach ($wrapper() as $value) {
echo $value, "\n";
}
?>
--EXPECT--
0
0

View File

@ -10,9 +10,6 @@ function from($levels) {
}
function gen($gen, $level) {
if ($level % 2) {
yield $gen->current();
}
yield from $gen;
}

View File

@ -609,6 +609,7 @@ void zend_generator_yield_from(zend_generator *generator, zend_generator *from)
generator->node.parent = from;
zend_generator_get_current(generator);
GC_DELREF(&from->std);
generator->flags |= ZEND_GENERATOR_DO_INIT;
}
ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator, zend_generator *leaf)
@ -785,6 +786,7 @@ try_again:
if (UNEXPECTED((orig_generator->flags & ZEND_GENERATOR_DO_INIT) != 0 && !Z_ISUNDEF(generator->value))) {
/* We must not advance Generator if we yield from a Generator being currently run */
orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT;
return;
}
@ -864,15 +866,15 @@ try_again:
goto try_again;
}
}
orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT;
}
/* }}} */
static inline void zend_generator_ensure_initialized(zend_generator *generator) /* {{{ */
{
if (UNEXPECTED(Z_TYPE(generator->value) == IS_UNDEF) && EXPECTED(generator->execute_data) && EXPECTED(generator->node.parent == NULL)) {
generator->flags |= ZEND_GENERATOR_DO_INIT;
zend_generator_resume(generator);
generator->flags &= ~ZEND_GENERATOR_DO_INIT;
generator->flags |= ZEND_GENERATOR_AT_FIRST_YIELD;
}
}