Skip to content

Commit cc6c200

Browse files
committed
1 parent 0e10531 commit cc6c200

File tree

6 files changed

+192
-0
lines changed

6 files changed

+192
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php // lint >= 8.1
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug11861;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
/**
10+
* @template T
11+
* @template K of array-key
12+
* @template R
13+
*
14+
* @param array<K, T> $source
15+
* @param callable(T, K): R $mappingFunction
16+
* @return array<K, R>
17+
*/
18+
function mapArray(array $source, callable $mappingFunction): array
19+
{
20+
$result = [];
21+
22+
foreach ($source as $key => $value) {
23+
$result[$key] = $mappingFunction($value, $key);
24+
}
25+
26+
return $result;
27+
}
28+
29+
/**
30+
* @template K
31+
* @template T
32+
*
33+
* @param array<K, null|T> $source
34+
* @return array<K, T>
35+
*/
36+
function filterArrayNotNull(array $source): array
37+
{
38+
return array_filter(
39+
$source,
40+
fn($item) => $item !== null,
41+
ARRAY_FILTER_USE_BOTH
42+
);
43+
}
44+
45+
/** @var list<array<string, null|int>> $a */
46+
$a = [];
47+
48+
$mappedA = mapArray(
49+
$a,
50+
static fn(array $entry) => filterArrayNotNull($entry)
51+
);
52+
53+
$mappedAWithFirstClassSyntax = mapArray(
54+
$a,
55+
filterArrayNotNull(...)
56+
);
57+
58+
assertType('array<int<0, max>, array<int|string, mixed>>', $mappedA);
59+
assertType('array<int<0, max>, array<int|string, mixed>>', $mappedAWithFirstClassSyntax);

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,4 +1921,22 @@ public function testBug12051(): void
19211921
$this->analyse([__DIR__ . '/data/bug-12051.php'], []);
19221922
}
19231923

1924+
public function testBug11942(): void
1925+
{
1926+
if (PHP_VERSION_ID < 80100) {
1927+
$this->markTestSkipped('Test requires PHP 8.1.');
1928+
}
1929+
1930+
$this->analyse([__DIR__ . '/data/bug-11942.php'], []);
1931+
}
1932+
1933+
public function testBug9167(): void
1934+
{
1935+
if (PHP_VERSION_ID < 80100) {
1936+
$this->markTestSkipped('Test requires PHP 8.1.');
1937+
}
1938+
1939+
$this->analyse([__DIR__ . '/data/bug-9167.php'], []);
1940+
}
1941+
19241942
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Bug11942;
4+
5+
/**
6+
* @template A
7+
* @param A $a
8+
* @return A
9+
*/
10+
function identity(mixed $a): mixed
11+
{
12+
return $a;
13+
}
14+
15+
/**
16+
* @param callable(int): int $fn
17+
*/
18+
function simple(callable $fn): int
19+
{
20+
return $fn(42);
21+
}
22+
23+
simple(identity(...));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Bug9167;
4+
5+
use Closure;
6+
7+
class A {
8+
/**
9+
* @template TRet
10+
* @param Closure(int):TRet $next
11+
* @return TRet
12+
*/
13+
public function __invoke(Closure $next) {
14+
return $next(12);
15+
}
16+
}
17+
18+
/**
19+
* @template T
20+
* @param T $in
21+
* @return T
22+
*/
23+
function value(mixed $in): mixed {
24+
return $in;
25+
}
26+
27+
function want_int(int $in): void {}
28+
29+
function pass_b(): void {
30+
$a = new A();
31+
want_int($a(value(...)));
32+
}

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3433,4 +3433,13 @@ public function testBug12691(): void
34333433
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-12691.php'], []);
34343434
}
34353435

3436+
public function testBug6828(): void
3437+
{
3438+
$this->checkThisOnly = false;
3439+
$this->checkNullables = true;
3440+
$this->checkUnionTypes = true;
3441+
$this->checkExplicitMixed = true;
3442+
$this->analyse([__DIR__ . '/data/bug-6828.php'], []);
3443+
}
3444+
34363445
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php // lint >= 8.1
2+
3+
declare(strict_types=1);
4+
5+
namespace Bug6828;
6+
7+
/** @template T */
8+
interface Option
9+
{
10+
/**
11+
* @template U
12+
* @param \Closure(T):U $c
13+
* @return Option<U>
14+
*/
15+
function map(\Closure $c);
16+
}
17+
18+
/**
19+
* @template T
20+
* @template E
21+
*/
22+
abstract class Result
23+
{
24+
/** @return T */
25+
function unwrap()
26+
{
27+
28+
}
29+
30+
/**
31+
* @template U
32+
* @param U $v
33+
* @return Result<U, mixed>
34+
*/
35+
static function ok($v)
36+
{
37+
38+
}
39+
}
40+
41+
/**
42+
* @template U
43+
* @template F
44+
* @param Result<Option<U>, F> $result
45+
* @return Option<Result<U, F>>
46+
*/
47+
function f(Result $result): Option
48+
{
49+
/** @var Option<Result<U, F>> */
50+
return $result->unwrap()->map(Result::ok(...));
51+
}

0 commit comments

Comments
 (0)