Skip to content

Commit 6d64074

Browse files
committed
1 parent ca41b7d commit 6d64074

File tree

5 files changed

+234
-0
lines changed

5 files changed

+234
-0
lines changed

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public function dataFileAsserts(): iterable
8383
yield from $this->gatherAssertTypes(__DIR__ . '/data/list-type.php');
8484
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2835.php');
8585
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2443.php');
86+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5508.php');
87+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10254.php');
8688
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2750.php');
8789
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2850.php');
8890
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2863.php');
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace Bug10254;
4+
5+
use Closure;
6+
use RuntimeException;
7+
use function PHPStan\Testing\assertType;
8+
9+
/**
10+
* @template T
11+
*/
12+
class Option {
13+
/**
14+
* @param T $value
15+
*/
16+
private function __construct(private mixed $value)
17+
{
18+
}
19+
20+
/**
21+
* @template Tv
22+
* @param Tv $value
23+
* @return self<Tv>
24+
*/
25+
public static function some($value): self
26+
{
27+
return new self($value);
28+
}
29+
30+
/**
31+
* @template Tu
32+
*
33+
* @param (Closure(T): Tu) $closure
34+
*
35+
* @return Option<Tu>
36+
*/
37+
public function map(Closure $closure): self
38+
{
39+
return new self($closure($this->unwrap()));
40+
}
41+
42+
/**
43+
* @return T
44+
*/
45+
public function unwrap()
46+
{
47+
if ($this->value === null) {
48+
throw new RuntimeException();
49+
}
50+
51+
return $this->value;
52+
}
53+
54+
/**
55+
* @template To
56+
* @param self<To> $other
57+
* @return self<array{0: T, 1: To}>
58+
*/
59+
public function zip(self $other)
60+
{
61+
return new self([
62+
$this->unwrap(),
63+
$other->unwrap()
64+
]);
65+
}
66+
}
67+
68+
69+
function (): void {
70+
$value = Option::some(1)
71+
->zip(Option::some(2));
72+
73+
assertType('Bug10254\\Option<array{int, int}>', $value);
74+
75+
$value1 = $value->map(function ($value) {
76+
assertType('int', $value[0]);
77+
assertType('int', $value[1]);
78+
return $value[0] + $value[1];
79+
});
80+
81+
assertType('Bug10254\\Option<int>', $value1);
82+
83+
$value2 = $value->map(function ($value): int {
84+
assertType('int', $value[0]);
85+
assertType('int', $value[1]);
86+
return $value[0] + $value[1];
87+
});
88+
89+
assertType('Bug10254\\Option<int>', $value2);
90+
91+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace Bug5508;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @template TKey as array-key
9+
* @template TValue
10+
*/
11+
class Collection
12+
{
13+
/**
14+
* @var array<TKey, TValue>
15+
*/
16+
protected $items = [];
17+
18+
/**
19+
* @param array<TKey, TValue> $items
20+
* @return void
21+
*/
22+
public function __construct($items)
23+
{
24+
$this->items = $items;
25+
}
26+
27+
/**
28+
* @template TMapValue
29+
*
30+
* @param callable(TValue, TKey): TMapValue $callback
31+
* @return self<TKey, TMapValue>
32+
*/
33+
public function map(callable $callback)
34+
{
35+
$keys = array_keys($this->items);
36+
37+
$items = array_map($callback, $this->items, $keys);
38+
39+
return new self(array_combine($keys, $items));
40+
}
41+
42+
/**
43+
* @return array<TKey, TValue>
44+
*/
45+
public function all()
46+
{
47+
return $this->items;
48+
}
49+
}
50+
51+
function (): void {
52+
$result = (new Collection(['book', 'cars']))->map(function($category) {
53+
return $category;
54+
})->all();
55+
56+
assertType('array<int, string>', $result);
57+
};

tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,4 +276,11 @@ public function testBug5592(): void
276276
$this->analyse([__DIR__ . '/data/bug-5592.php'], []);
277277
}
278278

279+
public function testBug10732(): void
280+
{
281+
$this->checkExplicitMixed = true;
282+
$this->checkNullables = true;
283+
$this->analyse([__DIR__ . '/data/bug-10732.php'], []);
284+
}
285+
279286
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Bug10732;
4+
5+
/**
6+
* @template-covariant TValue
7+
*/
8+
class Collection
9+
{
10+
/**
11+
* Create a new collection.
12+
*
13+
* @param list<TValue> $items
14+
* @return void
15+
*/
16+
public function __construct(protected array $items = []) {}
17+
18+
/**
19+
* Run a map over each of the items.
20+
*
21+
* @template TMapValue
22+
*
23+
* @param callable(TValue): TMapValue $callback
24+
* @return static<TMapValue>
25+
*/
26+
public function map(callable $callback)
27+
{
28+
return new self(array_map($callback, $this->items));
29+
}
30+
}
31+
32+
/**
33+
* I'd expect this to work?
34+
*
35+
* @param Collection<array<string, mixed>> $collection
36+
* @return Collection<array<string, mixed>>
37+
*/
38+
function current(Collection $collection): Collection
39+
{
40+
return $collection->map(fn(array $item) => $item);
41+
}
42+
43+
/**
44+
* Removing the Typehint works
45+
*
46+
* @param Collection<array<string, mixed>> $collection
47+
* @return Collection<array<string, mixed>>
48+
*/
49+
function removeTypeHint(Collection $collection): Collection
50+
{
51+
return $collection->map(fn($item) => $item);
52+
}
53+
54+
/**
55+
* Typehint works for simple type
56+
*
57+
* @param Collection<string> $collection
58+
* @return Collection<string>
59+
*/
60+
function simplerType(Collection $collection): Collection
61+
{
62+
return $collection->map(fn(string $item) => $item);
63+
}
64+
65+
/**
66+
* Typehint works for arrays
67+
*
68+
* @param array<string, array<string, mixed>> $collection
69+
* @return array<string, array<string, mixed>>
70+
*/
71+
function useArraysInstead(array $collection): array
72+
{
73+
return array_map(
74+
fn(array $item) => $item,
75+
$collection,
76+
);
77+
}

0 commit comments

Comments
 (0)