Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ parameters:
count: 5
path: src/Analyser/TypeSpecifier.php

-
rawMessage: 'Cannot call method getPathname() on SplFileInfo|string.'
identifier: method.nonObject
count: 1
path: src/Cache/FileCacheStorage.php

-
rawMessage: 'Template type TNodeType is declared as covariant, but occurs in contravariant position in parameter node of method PHPStan\Collectors\Collector::processNode().'
identifier: generics.variance
Expand Down
49 changes: 35 additions & 14 deletions stubs/iterable.stub
Original file line number Diff line number Diff line change
Expand Up @@ -159,22 +159,10 @@ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable
}

/**
* @template T of \RecursiveIterator|\IteratorAggregate
* @mixin T
* @implements SeekableIterator<string, DirectoryIterator>
*/
class RecursiveIteratorIterator
class DirectoryIterator extends SplFileInfo implements SeekableIterator
{
/**
* @param T $iterator
*/
public function __construct(
$iterator,
int $mode = RecursiveIteratorIterator::LEAVES_ONLY,
int $flags = 0
)
{

}

}

Expand Down Expand Up @@ -207,6 +195,31 @@ class IteratorIterator implements OuterIterator {
public function __construct(Traversable $iterator) {}
}

/**
* @template-covariant TKey
* @template-covariant TValue
* @template TIterator of \RecursiveIterator<TKey, TValue>|\IteratorAggregate<TKey, TValue>
Comment on lines +199 to +201
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it means that RecursiveIteratorIterator has now three template like

RecursiveIteratorIterator<int, int, IteratorAggregate<int, int>>

if so, it will break code where people used the single-template RecursiveIteratorIterator no ?

Also, this won't be compatible with the stub from psalm
https://github.com/vimeo/psalm/blob/ca151242c84d8962b921bf59c509b49362ce0eec/stubs/CoreGenericIterators.phpstub#L902-L903

*
* @implements OuterIterator<TKey, TValue>
*
* @mixin TIterator
*/
class RecursiveIteratorIterator implements OuterIterator
{
/**
* @param TIterator $iterator
*/
public function __construct(
$iterator,
int $mode = RecursiveIteratorIterator::LEAVES_ONLY,
int $flags = 0
)
{

}

}

/**
* @template-covariant TKey
* @template-covariant TValue
Expand Down Expand Up @@ -289,6 +302,14 @@ class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator
public function uksort($cmp_function) { }
}

/**
* @implements RecursiveIterator<string, SplFileInfo|string>
*/
class RecursiveDirectoryIterator extends FilesystemIterator implements RecursiveIterator
{

}

/**
* @template TKey
* @template TValue
Expand Down
26 changes: 26 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-8435.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

namespace Bug8435;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use function PHPStan\Testing\assertType;

class HelloWorld
{
public function sayHello1(string $path): void
{
$iterator = new RecursiveDirectoryIterator($path);
foreach ($iterator as $fileinfo) {
assertType('SplFileInfo|string', $fileinfo);
}
}

public function sayHello2(string $path): void
{
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
foreach ($iterator as $fileinfo) {
assertType('SplFileInfo|string', $fileinfo);
}
}
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/InstantiationRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ public function testBug3425(): void
{
$this->analyse([__DIR__ . '/data/bug-3425.php'], [
[
'Parameter #1 $iterator of class RecursiveIteratorIterator constructor expects T of IteratorAggregate|RecursiveIterator, Generator<int, int, mixed, void> given.',
'Parameter #1 $iterator of class RecursiveIteratorIterator constructor expects TIterator of IteratorAggregate<TKey, TValue>|RecursiveIterator<TKey, TValue>, Generator<int, int, mixed, void> given.',
5,
],
]);
Expand Down
Loading