Skip to content

Commit

Permalink
fix return type of parent calls for SplHeap
Browse files Browse the repository at this point in the history
  • Loading branch information
schlndh authored and ondrejmirtes committed Nov 18, 2023
1 parent 5a8168f commit aa6f456
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 12 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
],
"jetbrains/phpstorm-stubs": [
"patches/PDO.patch",
"patches/ReflectionProperty.patch",
"patches/SessionHandler.patch"
],
"rector/rector": [
Expand Down
18 changes: 9 additions & 9 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions patches/ReflectionProperty.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- Reflection/ReflectionProperty.php 2023-09-07 12:59:56.000000000 +0200
+++ Reflection/ReflectionProperty.php 2023-09-15 13:24:07.900736741 +0200
@@ -248,7 +248,7 @@
* Gets property type
*
* @link https://php.net/manual/en/reflectionproperty.gettype.php
- * @return ReflectionNamedType|ReflectionUnionType|null Returns a {@see ReflectionType} if the
+ * @return ReflectionType|null Returns a {@see ReflectionType} if the
* property has a type, and {@see null} otherwise.
* @since 7.4
*/
7 changes: 4 additions & 3 deletions src/Reflection/Php/PhpClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ private function createMethod(
$throwType = $throwsTag->getType();
}
$returnTag = $phpDocBlock->getReturnTag();
if ($returnTag !== null) {
if ($returnTag !== null && count($methodSignatures) === 1) {
$phpDocReturnType = $returnTag->getType();
}
foreach ($phpDocBlock->getParamTags() as $name => $paramTag) {
Expand Down Expand Up @@ -860,18 +860,19 @@ private function createNativeMethodVariant(
);
}

$returnType = null;
if ($stubPhpDocReturnType !== null) {
$returnType = $stubPhpDocReturnType;
$phpDocReturnType = $stubPhpDocReturnType;
} else {
$returnType = TypehintHelper::decideType($methodSignature->getReturnType(), $phpDocReturnType);
}

return new FunctionVariantWithPhpDocs(
TemplateTypeMap::createEmpty(),
null,
$parameters,
$methodSignature->isVariadic(),
$returnType ?? $methodSignature->getReturnType(),
$returnType,
$phpDocReturnType ?? new MixedType(),
$methodSignature->getNativeReturnType(),
);
Expand Down
4 changes: 4 additions & 0 deletions src/Type/TypehintHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ public static function decideType(
?Type $phpDocType = null,
): Type
{
if ($type instanceof BenevolentUnionType) {
return $type;
}

if ($phpDocType !== null && !$phpDocType instanceof ErrorType) {
if ($phpDocType instanceof NeverType && $phpDocType->isExplicit()) {
return $phpDocType;
Expand Down
3 changes: 3 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/generic-class-string.php');
if (PHP_VERSION_ID >= 80100) {
yield from $this->gatherAssertTypes(__DIR__ . '/data/generic-enum-class-string.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7162.php');
}

require_once __DIR__ . '/data/generic-generalization.php';
Expand Down Expand Up @@ -81,6 +82,7 @@ public function dataFileAsserts(): iterable

if (PHP_VERSION_ID >= 70400) {
yield from $this->gatherAssertTypes(__DIR__ . '/data/native-types.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/reflection-type.php');
}

if (PHP_VERSION_ID >= 80100) {
Expand Down Expand Up @@ -1368,6 +1370,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9963.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/str-shuffle.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9995.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9867.php');
}

/**
Expand Down
35 changes: 35 additions & 0 deletions tests/PHPStan/Analyser/data/bug-7162.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types=1); // lint >= 8.1

namespace Bug7162;

use function PHPStan\Testing\assertType;

class HelloWorld
{

/**
* @param class-string<\BackedEnum> $enumClassString
*/
public static function casesWithLabel(string $enumClassString): void
{
foreach ($enumClassString::cases() as $unitEnum) {
assertType('BackedEnum', $unitEnum);
}
}
}

enum Test{
case ONE;
}

/**
* @phpstan-template TEnum of \UnitEnum
* @phpstan-param TEnum $case
*/
function dumpCases(\UnitEnum $case) : void{
assertType('array<TEnum of UnitEnum (function Bug7162\\dumpCases(), argument)>', $case::cases());
}

function dumpCases2(Test $case) : void{
assertType('array{Bug7162\\Test::ONE}', $case::cases());
}
77 changes: 77 additions & 0 deletions tests/PHPStan/Analyser/data/bug-9867.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Bug9867;

use function PHPStan\Testing\assertType;

/** @extends \SplMinHeap<\DateTime> */
class MyMinHeap extends \SplMinHeap
{
public function test(): void
{
assertType('DateTime', parent::current());
assertType('DateTime', parent::extract());
assertType('DateTime', parent::top());
}

public function insert(mixed $value): bool
{
assertType('DateTime', $value);

return parent::insert($value);
}

protected function compare(mixed $value1, mixed $value2)
{
assertType('DateTime', $value1);
assertType('DateTime', $value2);

return parent::compare($value1, $value2);
}
}

/** @extends \SplMaxHeap<\DateTime> */
class MyMaxHeap extends \SplMaxHeap
{
public function test(): void
{
assertType('DateTime', parent::current());
assertType('DateTime', parent::extract());
assertType('DateTime', parent::top());
}

public function insert(mixed $value): bool
{
assertType('DateTime', $value);

return parent::insert($value);
}

protected function compare(mixed $value1, mixed $value2)
{
assertType('DateTime', $value1);
assertType('DateTime', $value2);

return parent::compare($value1, $value2);
}
}

/** @extends \SplHeap<\DateTime> */
abstract class MyHeap extends \SplHeap
{
public function test(): void
{
assertType('DateTime', parent::current());
assertType('DateTime', parent::extract());
assertType('DateTime', parent::top());
}

public function insert(mixed $value): bool
{
assertType('DateTime', $value);

return parent::insert($value);
}
}
15 changes: 15 additions & 0 deletions tests/PHPStan/Analyser/data/reflection-type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace ReflectionTypeTest;

use function PHPStan\Testing\assertType;

function test(
\ReflectionProperty $reflectionProperty,
\ReflectionFunctionAbstract $reflectionFunctionAbstract,
\ReflectionParameter $reflectionParameter
){
assertType('ReflectionType|null', $reflectionProperty->getType());
assertType('ReflectionType|null', $reflectionFunctionAbstract->getReturnType());
assertType('ReflectionType|null', $reflectionParameter->getType());
}

0 comments on commit aa6f456

Please sign in to comment.