Skip to content

Commit 94a2fe8

Browse files
committed
Regression test
Closes phpstan/phpstan#11283
1 parent fd31156 commit 94a2fe8

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,12 @@ public function testBug11147(): void
13941394
$this->assertSame('Method Bug11147\RedisAdapter::createConnection() has invalid return type Bug11147\NonExistentClass.', $errors[0]->getMessage());
13951395
}
13961396

1397+
public function testBug11283(): void
1398+
{
1399+
$errors = $this->runAnalyse(__DIR__ . '/data/bug-11283.php');
1400+
$this->assertNoErrors($errors);
1401+
}
1402+
13971403
/**
13981404
* @param string[]|null $allAnalysedFiles
13991405
* @return Error[]
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug11283;
4+
5+
/**
6+
* @return mixed
7+
*/
8+
function returnMixed()
9+
{
10+
return 1;
11+
}
12+
13+
/**
14+
* Partial copy of https://github.com/reactphp/promise/blob/3.x/src/PromiseInterface.php
15+
* @template-covariant T
16+
*/
17+
interface PromiseInterface
18+
{
19+
/**
20+
* @template TFulfilled
21+
* @template TRejected
22+
* @param ?(callable((T is void ? null : T)): (PromiseInterface<TFulfilled>|TFulfilled)) $onFulfilled
23+
* @param ?(callable(\Throwable): (PromiseInterface<TRejected>|TRejected)) $onRejected
24+
* @return PromiseInterface<($onRejected is null ? ($onFulfilled is null ? T : TFulfilled) : ($onFulfilled is null ? T|TRejected : TFulfilled|TRejected))>
25+
*/
26+
public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface;
27+
28+
/**
29+
* @template TThrowable of \Throwable
30+
* @template TRejected
31+
* @param callable(TThrowable): (PromiseInterface<TRejected>|TRejected) $onRejected
32+
* @return PromiseInterface<T|TRejected>
33+
*/
34+
public function catch(callable $onRejected): PromiseInterface;
35+
36+
/**
37+
* @param callable(): (void|PromiseInterface<void>) $onFulfilledOrRejected
38+
* @return PromiseInterface<T>
39+
*/
40+
public function finally(callable $onFulfilledOrRejected): PromiseInterface;
41+
}
42+
43+
/**
44+
* @template T
45+
* @param PromiseInterface<T>|T $promiseOrValue
46+
* @return PromiseInterface<T>
47+
*/
48+
function resolve($promiseOrValue): PromiseInterface
49+
{
50+
return returnMixed();
51+
}
52+
53+
class Demonstration
54+
{
55+
public function parseMessage(): void
56+
{
57+
$params = [];
58+
$packet = [];
59+
$promise = resolve(null);
60+
61+
$promise->then(function () use (&$packet, &$params) {
62+
if (mt_rand(0, 1)) {
63+
resolve(null)->then(
64+
function () use ($packet, &$params) {
65+
$packet['payload']['type'] = 0;
66+
$this->groupNotify(
67+
$packet,
68+
function () use ($packet, &$params) {
69+
$this->save($packet, $params)->then(function () use ($packet, &$params) {
70+
if ($params['links']) {
71+
$this->handle($params)->then(function ($result) use ($packet) {
72+
if ($result) {
73+
$packet['payload']['preview'] = $result;
74+
}
75+
});
76+
}
77+
});
78+
}
79+
);
80+
}
81+
);
82+
} else {
83+
$this->call(function () use (&$params) {
84+
$packet['target'] = [];
85+
86+
$this->asyncAction()->then(function ($value) use (&$packet, &$params) {
87+
if (!$value) {
88+
$packet['payload']['type'] = 0;
89+
$packet['payload']['message'] = '';
90+
$this->selfNotify($packet);
91+
return;
92+
}
93+
94+
$packet['payload']['type'] = 0;
95+
$this->groupNotify(
96+
$packet,
97+
function () use ($packet, &$params) {
98+
$this->save($packet, $params)->then(function () use ($packet, &$params) {
99+
if ($params) {
100+
$this->handle($params)->then(function ($result) use ($packet) {
101+
if ($result) {
102+
$packet['payload']['preview'] = $result;
103+
$this->selfNotify($packet);
104+
}
105+
});
106+
}
107+
});
108+
}
109+
);
110+
});
111+
});
112+
}
113+
});
114+
}
115+
116+
/**
117+
* @return PromiseInterface<mixed>
118+
*/
119+
private function handle(mixed $params): PromiseInterface
120+
{
121+
return resolve(null);
122+
}
123+
124+
/**
125+
* @param array<string, mixed> $packet
126+
* @param array<string, mixed> $params
127+
* @return PromiseInterface<int>
128+
*/
129+
private function save(array $packet, array &$params): PromiseInterface
130+
{
131+
return resolve(0);
132+
}
133+
134+
/**
135+
* @param array<string, mixed> $packet
136+
* @param (callable():void) $callback
137+
* @return bool
138+
*/
139+
public function groupNotify(array $packet, callable $callback): bool
140+
{
141+
return true;
142+
}
143+
144+
/**
145+
* @param array<string, mixed> $packet
146+
* @return bool
147+
*/
148+
public function selfNotify(array $packet): bool
149+
{
150+
return true;
151+
}
152+
153+
/**
154+
* @return PromiseInterface<mixed>
155+
*/
156+
private function asyncAction(): PromiseInterface
157+
{
158+
return resolve('');
159+
}
160+
161+
/**
162+
* @param callable():void $callback
163+
*/
164+
private function call(callable $callback): void
165+
{
166+
}
167+
}
168+

0 commit comments

Comments
 (0)