Skip to content

Generator with double enclosed yield from and valid call will skip items #15375

Description

@malofan

Description

The following code:

<?php

function arrayProvider()
{
	yield [
		'one',
		'two',
		'three',
	];
	
	yield [
		'four',
		'five',
		'six',
	];
	
	yield [
		'seven',
		'eight',
		'nine',
	];
}

function iterateValues(array $array)
{
    foreach ($array as $value) {
    	yield $value;
    }
}

function g1() {
    foreach (arrayProvider() as $array) {
        $iterator = iterateValues($array);
        
        if ($iterator?->valid()) {
            yield from $iterator;
        }
    }
}

function g2() {
	yield from g1();
}

foreach (g2() as $s) {
	echo $s . PHP_EOL;
}

Resulted in this output:

one
two
three
five
six
eight
nine

But I expected this output instead:

one
two
three
four
five
six
seven
eight
nine

https://3v4l.org/GdcNh

So if we in g2 we'll try to yield from generator g1() AND in g1 we'll try to yield from generator iterateValues() BUT will call valid for it before then this valid call will move pointer to next element of generator.

It replicates ONLY with yield from -> yield from combination AND valid call inside.
Removing valid call or one yield from, as well as replacing yield from generator iterateValues() to foreach: yield will solve the problem.

Also in test done by @lifinsky were found that following code in g1:

$iterator->next();
yield from $iterator;

Resulted in this output:

two
three
six
nine

When expected:

two
three
five
six
eight
nine

https://3v4l.org/Aq6NF

So next call also jumps and results in missed values.

PHP Version

7.0.0 - 7.0.33, 7.1.0 - 7.1.33, 7.2.0 - 7.2.34, 7.3.0 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.29, 8.2.0 - 8.2.22, 8.3.0 - 8.3.10, 8.4.1

Operating System

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions