Skip to content

Commit adab2a0

Browse files
committed
fix multiple return type bugs
1 parent 3c577ca commit adab2a0

File tree

5 files changed

+136
-5
lines changed

5 files changed

+136
-5
lines changed

Diff for: src/EventHandler/Iter/Count/FunctionReturnTypeProvider.php

+17-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ final class FunctionReturnTypeProvider implements FunctionReturnTypeProviderInte
1919
public static function getFunctionIds(): array
2020
{
2121
return [
22-
'psl\str\count',
22+
'psl\iter\count',
2323
];
2424
}
2525

@@ -56,7 +56,22 @@ public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $ev
5656

5757
// array{foo: bar} -> literal-int(1)
5858
if ($array_argument_type instanceof Type\Atomic\TKeyedArray) {
59-
return Type::getInt(false, count($array_argument_type->properties));
59+
// Psalm allows extra properties in keyed arrays, so we can't return a literal integer
60+
// for this.
61+
//
62+
// return Type::getInt(false, count($array_argument_type->properties));
63+
64+
if (count($array_argument_type->properties) >= 1) {
65+
return Type::getPositiveInt();
66+
}
67+
68+
return Type::getInt();
69+
}
70+
71+
if ($array_argument_type instanceof Type\Atomic\TArray) {
72+
if ($array_argument_type->type_params[0]->isEmpty() && $array_argument_type->type_params[1]->isEmpty()) {
73+
return Type::getInt(false, 0);
74+
}
6075
}
6176

6277
return Type::getInt();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Psl\Psalm\EventHandler\Iter\FirstKey;
6+
7+
use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent;
8+
use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface;
9+
use Psalm\Type;
10+
use Psl\Psalm\Argument;
11+
12+
final class FunctionReturnTypeProvider implements FunctionReturnTypeProviderInterface
13+
{
14+
/**
15+
* @return non-empty-list<lowercase-string>
16+
*/
17+
public static function getFunctionIds(): array
18+
{
19+
return [
20+
'psl\iter\first_key',
21+
];
22+
}
23+
24+
public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Type\Union
25+
{
26+
$argument_type = Argument::getType($event->getCallArgs(), $event->getStatementsSource(), 0);
27+
if (null === $argument_type) {
28+
return null;
29+
}
30+
31+
$array_argument_type = $argument_type->getAtomicTypes()['array'] ?? null;
32+
if (null === $array_argument_type) {
33+
return null;
34+
}
35+
36+
if ($array_argument_type instanceof Type\Atomic\TNonEmptyArray) {
37+
return clone $array_argument_type->type_params[0];
38+
}
39+
40+
if ($array_argument_type instanceof Type\Atomic\TNonEmptyList) {
41+
return Type::getInt();
42+
}
43+
44+
if ($array_argument_type instanceof Type\Atomic\TKeyedArray) {
45+
// TODO(azjezz): add support for this once psalm starts enforcing the shape order ( if ever ).
46+
//
47+
// foreach ($properties as $property) {
48+
// return clone $property;
49+
// }
50+
return clone $array_argument_type->getGenericKeyType();
51+
}
52+
53+
return null;
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Psl\Psalm\EventHandler\Iter\LastKey;
6+
7+
use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent;
8+
use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface;
9+
use Psalm\Type;
10+
use Psl\Psalm\Argument;
11+
12+
final class FunctionReturnTypeProvider implements FunctionReturnTypeProviderInterface
13+
{
14+
/**
15+
* @return non-empty-list<lowercase-string>
16+
*/
17+
public static function getFunctionIds(): array
18+
{
19+
return [
20+
'psl\iter\last_key',
21+
];
22+
}
23+
24+
public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Type\Union
25+
{
26+
$argument_type = Argument::getType($event->getCallArgs(), $event->getStatementsSource(), 0);
27+
if (null === $argument_type) {
28+
return null;
29+
}
30+
31+
$array_argument_type = $argument_type->getAtomicTypes()['array'] ?? null;
32+
if (null === $array_argument_type) {
33+
return null;
34+
}
35+
36+
if ($array_argument_type instanceof Type\Atomic\TNonEmptyArray) {
37+
return clone $array_argument_type->type_params[0];
38+
}
39+
40+
if ($array_argument_type instanceof Type\Atomic\TNonEmptyList) {
41+
return Type::getInt();
42+
}
43+
44+
if ($array_argument_type instanceof Type\Atomic\TKeyedArray) {
45+
// TODO(azjezz): add support for this once psalm starts enforcing the shape order ( if ever ).
46+
//
47+
// $properties = $array_argument_type->properties;
48+
// $last_property = null;
49+
// foreach ($properties as $property) {
50+
// $last_property = $property;
51+
// }
52+
//
53+
// return clone $last_property;
54+
return clone $array_argument_type->getGenericKeyType();
55+
}
56+
57+
return null;
58+
}
59+
}

Diff for: src/EventHandler/Str/Repeat/FunctionReturnTypeProvider.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static function getFunctionIds(): array
2626
public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Type\Union
2727
{
2828
$argument_type = Argument::getType($event->getCallArgs(), $event->getStatementsSource(), 0);
29-
if ($argument_type === null || !$argument_type->hasLowercaseString()) {
29+
if ($argument_type === null) {
3030
return Type::getString();
3131
}
3232

@@ -43,12 +43,12 @@ public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $ev
4343
return new Type\Union([new Type\Atomic\TLowercaseString()]);
4444
}
4545

46-
if ($string_argument_type instanceof Type\Atomic\TLiteralString) {
46+
if ($argument_type->hasLiteralString()) {
4747
$multiplier_argument_type = Argument::getType($event->getCallArgs(), $event->getStatementsSource(), 1);
4848
if (null !== $multiplier_argument_type && $multiplier_argument_type->hasLiteralInt()) {
4949
/** @psalm-suppress MissingThrowsDocblock */
5050
return Type::getString(str_repeat(
51-
$string_argument_type->value,
51+
$argument_type->getSingleStringLiteral()->value,
5252
$multiplier_argument_type->getSingleIntLiteral()->value
5353
));
5454
}

Diff for: src/Plugin.php

+2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ private function getHooks(): iterable
3131
{
3232
// Psl\Iter hooks
3333
yield EventHandler\Iter\First\FunctionReturnTypeProvider::class;
34+
yield EventHandler\Iter\FirstKey\FunctionReturnTypeProvider::class;
3435
yield EventHandler\Iter\Last\FunctionReturnTypeProvider::class;
36+
yield EventHandler\Iter\LastKey\FunctionReturnTypeProvider::class;
3537
yield EventHandler\Iter\Count\FunctionReturnTypeProvider::class;
3638

3739
// Psl\Regex hooks

0 commit comments

Comments
 (0)