Skip to content

Commit 0ef3c87

Browse files
schlndhondrejmirtes
authored andcommitted
fix return type of parent calls for SplHeap
1 parent f083c2e commit 0ef3c87

9 files changed

+159
-12
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
],
9595
"jetbrains/phpstorm-stubs": [
9696
"patches/PDO.patch",
97+
"patches/ReflectionProperty.patch",
9798
"patches/SessionHandler.patch"
9899
],
99100
"rector/rector": [

composer.lock

+9-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

patches/ReflectionProperty.patch

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--- Reflection/ReflectionProperty.php 2023-09-07 12:59:56.000000000 +0200
2+
+++ Reflection/ReflectionProperty.php 2023-09-15 13:24:07.900736741 +0200
3+
@@ -248,7 +248,7 @@
4+
* Gets property type
5+
*
6+
* @link https://php.net/manual/en/reflectionproperty.gettype.php
7+
- * @return ReflectionNamedType|ReflectionUnionType|null Returns a {@see ReflectionType} if the
8+
+ * @return ReflectionType|null Returns a {@see ReflectionType} if the
9+
* property has a type, and {@see null} otherwise.
10+
* @since 7.4
11+
*/

src/Reflection/Php/PhpClassReflectionExtension.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ private function createMethod(
595595
$throwType = $throwsTag->getType();
596596
}
597597
$returnTag = $phpDocBlock->getReturnTag();
598-
if ($returnTag !== null) {
598+
if ($returnTag !== null && count($methodSignatures) === 1) {
599599
$phpDocReturnType = $returnTag->getType();
600600
}
601601
foreach ($phpDocBlock->getParamTags() as $name => $paramTag) {
@@ -860,18 +860,19 @@ private function createNativeMethodVariant(
860860
);
861861
}
862862

863-
$returnType = null;
864863
if ($stubPhpDocReturnType !== null) {
865864
$returnType = $stubPhpDocReturnType;
866865
$phpDocReturnType = $stubPhpDocReturnType;
866+
} else {
867+
$returnType = TypehintHelper::decideType($methodSignature->getReturnType(), $phpDocReturnType);
867868
}
868869

869870
return new FunctionVariantWithPhpDocs(
870871
TemplateTypeMap::createEmpty(),
871872
null,
872873
$parameters,
873874
$methodSignature->isVariadic(),
874-
$returnType ?? $methodSignature->getReturnType(),
875+
$returnType,
875876
$phpDocReturnType ?? new MixedType(),
876877
$methodSignature->getNativeReturnType(),
877878
);

src/Type/TypehintHelper.php

+4
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ public static function decideType(
162162
?Type $phpDocType = null,
163163
): Type
164164
{
165+
if ($type instanceof BenevolentUnionType) {
166+
return $type;
167+
}
168+
165169
if ($phpDocType !== null && !$phpDocType instanceof ErrorType) {
166170
if ($phpDocType instanceof NeverType && $phpDocType->isExplicit()) {
167171
return $phpDocType;

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function dataFileAsserts(): iterable
4040
yield from $this->gatherAssertTypes(__DIR__ . '/data/generic-class-string.php');
4141
if (PHP_VERSION_ID >= 80100) {
4242
yield from $this->gatherAssertTypes(__DIR__ . '/data/generic-enum-class-string.php');
43+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7162.php');
4344
}
4445

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

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

8688
if (PHP_VERSION_ID >= 80100) {
@@ -1369,6 +1371,7 @@ public function dataFileAsserts(): iterable
13691371
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9963.php');
13701372
yield from $this->gatherAssertTypes(__DIR__ . '/data/str-shuffle.php');
13711373
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9995.php');
1374+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9867.php');
13721375
}
13731376

13741377
/**
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php declare(strict_types=1); // lint >= 8.1
2+
3+
namespace Bug7162;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
10+
/**
11+
* @param class-string<\BackedEnum> $enumClassString
12+
*/
13+
public static function casesWithLabel(string $enumClassString): void
14+
{
15+
foreach ($enumClassString::cases() as $unitEnum) {
16+
assertType('BackedEnum', $unitEnum);
17+
}
18+
}
19+
}
20+
21+
enum Test{
22+
case ONE;
23+
}
24+
25+
/**
26+
* @phpstan-template TEnum of \UnitEnum
27+
* @phpstan-param TEnum $case
28+
*/
29+
function dumpCases(\UnitEnum $case) : void{
30+
assertType('array<TEnum of UnitEnum (function Bug7162\\dumpCases(), argument)>', $case::cases());
31+
}
32+
33+
function dumpCases2(Test $case) : void{
34+
assertType('array{Bug7162\\Test::ONE}', $case::cases());
35+
}
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Bug9867;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
/** @extends \SplMinHeap<\DateTime> */
10+
class MyMinHeap extends \SplMinHeap
11+
{
12+
public function test(): void
13+
{
14+
assertType('DateTime', parent::current());
15+
assertType('DateTime', parent::extract());
16+
assertType('DateTime', parent::top());
17+
}
18+
19+
public function insert(mixed $value): bool
20+
{
21+
assertType('DateTime', $value);
22+
23+
return parent::insert($value);
24+
}
25+
26+
protected function compare(mixed $value1, mixed $value2)
27+
{
28+
assertType('DateTime', $value1);
29+
assertType('DateTime', $value2);
30+
31+
return parent::compare($value1, $value2);
32+
}
33+
}
34+
35+
/** @extends \SplMaxHeap<\DateTime> */
36+
class MyMaxHeap extends \SplMaxHeap
37+
{
38+
public function test(): void
39+
{
40+
assertType('DateTime', parent::current());
41+
assertType('DateTime', parent::extract());
42+
assertType('DateTime', parent::top());
43+
}
44+
45+
public function insert(mixed $value): bool
46+
{
47+
assertType('DateTime', $value);
48+
49+
return parent::insert($value);
50+
}
51+
52+
protected function compare(mixed $value1, mixed $value2)
53+
{
54+
assertType('DateTime', $value1);
55+
assertType('DateTime', $value2);
56+
57+
return parent::compare($value1, $value2);
58+
}
59+
}
60+
61+
/** @extends \SplHeap<\DateTime> */
62+
abstract class MyHeap extends \SplHeap
63+
{
64+
public function test(): void
65+
{
66+
assertType('DateTime', parent::current());
67+
assertType('DateTime', parent::extract());
68+
assertType('DateTime', parent::top());
69+
}
70+
71+
public function insert(mixed $value): bool
72+
{
73+
assertType('DateTime', $value);
74+
75+
return parent::insert($value);
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace ReflectionTypeTest;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
function test(
8+
\ReflectionProperty $reflectionProperty,
9+
\ReflectionFunctionAbstract $reflectionFunctionAbstract,
10+
\ReflectionParameter $reflectionParameter
11+
){
12+
assertType('ReflectionType|null', $reflectionProperty->getType());
13+
assertType('ReflectionType|null', $reflectionFunctionAbstract->getReturnType());
14+
assertType('ReflectionType|null', $reflectionParameter->getType());
15+
}

0 commit comments

Comments
 (0)