diff --git a/src/Analyser/ExprHandler/NewHandler.php b/src/Analyser/ExprHandler/NewHandler.php index 4179b5259d..534b0373c3 100644 --- a/src/Analyser/ExprHandler/NewHandler.php +++ b/src/Analyser/ExprHandler/NewHandler.php @@ -547,6 +547,10 @@ classReflection: $classReflection->withTypes($types)->asFinal(), continue; } + if ($type instanceof NeverType) { + continue; + } + if (!array_key_exists($ancestorType->getName(), $resolvedTypeMap)) { $resolvedTypeMap[$ancestorType->getName()] = $type; continue; diff --git a/tests/PHPStan/Analyser/nsrt/bug-14281.php b/tests/PHPStan/Analyser/nsrt/bug-14281.php new file mode 100644 index 0000000000..1433cc0008 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14281.php @@ -0,0 +1,99 @@ + 'value'], + ]; + + $collection = (new TestCollection())->assignRecursive($data); + + assert(count($collection)===5); + assertType("array{null, 0, 'some-string', stdClass, array{some: 'value'}}", $data); + + assert($data[0] === $collection->get(0)); + assertType("array{null, 0, 'some-string', stdClass, array{some: 'value'}}", $data); + assert($data[1] === $collection->get(1)); + assertType("array{null, 0, 'some-string', stdClass, array{some: 'value'}}", $data); + assert($data[2] === $collection->get(2)); + assertType("array{null, 0, 'some-string', stdClass, array{some: 'value'}}", $data); + assert($data[3] === $collection->get(3)); + assertType("array{null, 0, 'some-string', stdClass, array{some: 'value'}}", $data); + assert($data[4] === $collection->get(4)); + assertType("array{null, 0, 'some-string', stdClass, array{some: 'value'}}", $data); + } +} + +/** + * @template TElement + * + * @extends Collection + */ +class TestCollection extends Collection +{ +} + +/** + * @template TElement + * + * @implements \IteratorAggregate + */ +abstract class Collection implements \IteratorAggregate, \Countable +{ + /** + * @var array + */ + protected array $elements = []; + + /** + * @param array $elements + */ + public function __construct(array $elements = []) + { + $this->elements = $elements; + } + + /** + * @param array-key $key + * + * @return TElement|null + */ + public function get($key) + { + return $this->elements[$key] ?? null; + } + + /** + * @phpstan-impure + */ + #[\Override] + public function count(): int + { + return \count($this->elements); + } + + /** + * @return \Traversable + */ + #[\Override] + public function getIterator(): \Traversable + { + yield from $this->elements; + } + + /** @param array $options */ + public function assignRecursive(array $options): static + { + return $this; + } +}