Skip to content

Commit 330eb22

Browse files
committed
Fix DsMapDynamicReturnTypeExtension
1 parent 10a2b24 commit 330eb22

File tree

3 files changed

+72
-7
lines changed

3 files changed

+72
-7
lines changed

src/Type/Php/DsMapDynamicReturnTypeExtension.php

+23-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Reflection\ParametersAcceptorSelector;
99
use PHPStan\Type\DynamicMethodReturnTypeExtension;
1010
use PHPStan\Type\Generic\TemplateType;
11+
use PHPStan\Type\Generic\TemplateTypeScope;
1112
use PHPStan\Type\Type;
1213
use PHPStan\Type\TypeCombinator;
1314
use PHPStan\Type\UnionType;
@@ -27,22 +28,33 @@ public function isMethodSupported(MethodReflection $methodReflection): bool
2728

2829
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
2930
{
30-
$returnType = $methodReflection->getVariants()[0]->getReturnType();
31+
$returnType = ParametersAcceptorSelector::selectFromArgs(
32+
$scope,
33+
$methodCall->args,
34+
$methodReflection->getVariants()
35+
)->getReturnType();
3136

3237
if (count($methodCall->args) > 1) {
33-
return ParametersAcceptorSelector::selectFromArgs(
34-
$scope,
35-
$methodCall->args,
36-
$methodReflection->getVariants()
37-
)->getReturnType();
38+
return $returnType;
3839
}
3940

4041
if ($returnType instanceof UnionType) {
4142
$types = array_values(
4243
array_filter(
4344
$returnType->getTypes(),
4445
static function (Type $type): bool {
45-
return !$type instanceof TemplateType;
46+
if (
47+
$type instanceof TemplateType
48+
&& $type->getName() === 'TDefault'
49+
&& (
50+
$type->getScope()->equals(TemplateTypeScope::createWithMethod('Ds\Map', 'get'))
51+
|| $type->getScope()->equals(TemplateTypeScope::createWithMethod('Ds\Map', 'remove'))
52+
)
53+
) {
54+
return false;
55+
}
56+
57+
return true;
4658
}
4759
)
4860
);
@@ -51,6 +63,10 @@ static function (Type $type): bool {
5163
return $types[0];
5264
}
5365

66+
if (count($types) === 0) {
67+
return $returnType;
68+
}
69+
5470
return TypeCombinator::union(...$types);
5571
}
5672

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -5695,6 +5695,11 @@ public function dataBug4707(): array
56955695
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4707.php');
56965696
}
56975697

5698+
public function dataBug4545(): array
5699+
{
5700+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4545.php');
5701+
}
5702+
56985703
/**
56995704
* @dataProvider dataArrayFunctions
57005705
* @param string $description
@@ -11317,6 +11322,7 @@ private function gatherAssertTypes(string $file): array
1131711322
* @dataProvider dataBug4213
1131811323
* @dataProvider dataBug4657
1131911324
* @dataProvider dataBug4707
11325+
* @dataProvider dataBug4545
1132011326
* @param string $assertType
1132111327
* @param string $file
1132211328
* @param mixed ...$args
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Bug4545;
4+
5+
use Closure;
6+
use Ds\Hashable;
7+
use Ds\Map;
8+
use Ds\Set;
9+
use function PHPStan\Analyser\assertType;
10+
11+
class Foo
12+
{
13+
14+
/**
15+
* Returns keys which either exist only in one of the maps or exist in both but their associated values are not equal.
16+
*
17+
* @template TKey of Hashable
18+
* @template TValue1
19+
* @template TValue2
20+
*
21+
* @param Map<TKey, TValue1> $firstMap
22+
* @param Map<TKey, TValue2> $secondMap
23+
* @param Closure(TValue1, TValue2): bool $comparator
24+
*
25+
* @return Set<TKey>
26+
*/
27+
function compareMaps(Map $firstMap, Map $secondMap, Closure $comparator): Set
28+
{
29+
$firstMapKeys = $firstMap->keys();
30+
$secondMapKeys = $secondMap->keys();
31+
$keys = $firstMapKeys->xor($secondMapKeys);
32+
$intersect = $firstMapKeys->intersect($secondMapKeys);
33+
foreach ($intersect as $key) {
34+
assertType('TValue1 (method Bug4545\Foo::compareMaps(), argument)', $firstMap->get($key));
35+
assertType('TValue2 (method Bug4545\Foo::compareMaps(), argument)', $secondMap->get($key));
36+
assertType('int|TValue2 (method Bug4545\Foo::compareMaps(), argument)', $secondMap->get($key, 1));
37+
}
38+
39+
return $keys;
40+
}
41+
42+
}
43+

0 commit comments

Comments
 (0)