Skip to content

Commit f7a7326

Browse files
committed
1 parent b3be025 commit f7a7326

File tree

7 files changed

+158
-1
lines changed

7 files changed

+158
-1
lines changed

changelog-2.0.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Improvements 🔧
131131
* No implicit wildcard in FileExcluder (https://github.com/phpstan/phpstan-src/commit/e19e6e5f8cfa706cc30e44a17276a6bc269f995c), #10299
132132
* Report invalid exclude paths in PHP config (https://github.com/phpstan/phpstan-src/commit/9718c14f1ffac81ba3d2bf331b4e8b4041a4d004)
133133
* Do not generalize template types, except when in `GenericObjectType` ([#2818](https://github.com/phpstan/phpstan-src/pull/2818), [#2821](https://github.com/phpstan/phpstan-src/pull/2821))
134-
* This fixes following **17 issues**: #8166, #8127, #7944, #7283, #6653, #6196, #9084, #8683, #8074, #7984, #7301, #7087, #5594, #5592, #9472, #9764, #10092
134+
* This fixes following **20 issues**: #8166, #8127, #7944, #7283, #6653, #6196, #9084, #8683, #8074, #7984, #7301, #7087, #5594, #5592, #9472, #9764, #10092, #11126, #11032, #10653
135135
* Non-static methods cannot be used as static callables in PHP 8+ ([#2420](https://github.com/phpstan/phpstan-src/pull/2420)), thanks @staabm!
136136
* Analysis with zero files results in non-zero exit code (https://github.com/phpstan/phpstan-src/commit/46ff440648e62617df86aa74ba905ffa99897737), #9410
137137
* Fail build when project config uses custom extensions outside of analysed paths
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Bug10653;
4+
5+
use stdClass;
6+
use function PHPStan\Testing\assertType;
7+
8+
function (A $a): void {
9+
$value = $a->mayFail();
10+
assertType('stdClass|false', $value);
11+
$value = $a->throwOnFailure($value);
12+
assertType(stdClass::class, $value);
13+
};

tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,18 @@ public function testBug8881(): void
301301
$this->analyse([__DIR__ . '/data/bug-8881.php'], []);
302302
}
303303

304+
public function testBug11126(): void
305+
{
306+
$this->checkExplicitMixed = true;
307+
$this->checkNullables = true;
308+
$this->analyse([__DIR__ . '/data/bug-11126.php'], []);
309+
}
310+
311+
public function testBug11032(): void
312+
{
313+
$this->checkExplicitMixed = true;
314+
$this->checkNullables = true;
315+
$this->analyse([__DIR__ . '/data/bug-11032.php'], []);
316+
}
317+
304318
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Bug11032;
4+
5+
/**
6+
* @template-covariant T
7+
*/
8+
interface PromiseInterface
9+
{
10+
}
11+
12+
/**
13+
* @template T
14+
*/
15+
final class Deferred
16+
{
17+
/**
18+
* @var PromiseInterface<T>
19+
*/
20+
private $promise = null;
21+
22+
/**
23+
* @return PromiseInterface<T>
24+
*/
25+
public function promise(): PromiseInterface
26+
{
27+
return $this->promise;
28+
}
29+
}
30+
31+
/**
32+
* @template T
33+
* @param iterable<T> $tasks
34+
* @return PromiseInterface<array<T>>
35+
*/
36+
function parallel(iterable $tasks): PromiseInterface
37+
{
38+
/** @var Deferred<array<T>> $deferred*/
39+
$deferred = new Deferred();
40+
41+
return $deferred->promise();
42+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Bug11126;
4+
5+
/**
6+
* @template T
7+
*/
8+
class Collection {
9+
/**
10+
* @template TRet
11+
* @param (callable(T): TRet) $callback
12+
* @return static<TRet>
13+
*/
14+
public function map(callable $callback): Collection {
15+
return $this;
16+
}
17+
}
18+
19+
/**
20+
* @param Collection<int<0, max>> $in
21+
* @return Collection<int<0, max>>
22+
*/
23+
function foo(Collection $in): Collection {
24+
return $in->map(static fn ($v) => $v);
25+
}
26+
27+
/**
28+
* @param Collection<int<0, max>> $in
29+
* @return Collection<int<0, max>>
30+
*/
31+
function bar(Collection $in): Collection {
32+
return $in->map(value(...));
33+
}
34+
35+
/**
36+
* @param int<0, max> $in
37+
* @return int<0, max>
38+
*/
39+
function value(int $in): int {
40+
return $in;
41+
}

tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,4 +1081,9 @@ public function testBug10715(): void
10811081
$this->analyse([__DIR__ . '/data/bug-10715.php'], []);
10821082
}
10831083

1084+
public function testBug10653(): void
1085+
{
1086+
$this->analyse([__DIR__ . '/data/bug-10653.php'], []);
1087+
}
1088+
10841089
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Bug10653;
4+
5+
use stdClass;
6+
use Exception;
7+
8+
class A
9+
{
10+
private int $Counter = 0;
11+
12+
/**
13+
* @return stdClass
14+
*/
15+
public function getMayFail()
16+
{
17+
return $this->throwOnFailure($this->mayFail());
18+
}
19+
20+
/**
21+
* @template T
22+
*
23+
* @param T $result
24+
* @return (T is false ? never : T)
25+
*/
26+
public function throwOnFailure($result)
27+
{
28+
if ($result === false) {
29+
throw new Exception('Operation failed');
30+
}
31+
return $result;
32+
}
33+
34+
/**
35+
* @return stdClass|false
36+
*/
37+
public function mayFail()
38+
{
39+
$this->Counter++;
40+
return $this->Counter % 2 ? new stdClass() : false;
41+
}
42+
}

0 commit comments

Comments
 (0)