From e77743c7df83ae20e0bb629371d8600448e5d5e8 Mon Sep 17 00:00:00 2001 From: Etienne Zannelli Date: Fri, 29 Oct 2021 18:52:55 +0200 Subject: [PATCH] feat: add some typing for static analysis --- src/Adapter/Tornado/EventLoop.php | 2 ++ src/EventLoop.php | 33 +++++++++++++++++++--- src/HttpClient.php | 3 ++ src/Promise.php | 3 ++ tests/Adapter/Guzzle/GuzzleMockWrapper.php | 3 -- tests/EventLoopTest/AsyncTest.php | 3 ++ tests/EventLoopTest/PromiseForeachTest.php | 1 + 7 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/Adapter/Tornado/EventLoop.php b/src/Adapter/Tornado/EventLoop.php index 546c5d3..4984fcd 100644 --- a/src/Adapter/Tornado/EventLoop.php +++ b/src/Adapter/Tornado/EventLoop.php @@ -237,6 +237,8 @@ public function delay(int $milliseconds): Promise while (microtime(true) < $endTime) { yield $this->idle(); } + + return null; })()); } diff --git a/src/EventLoop.php b/src/EventLoop.php index fddd33f..4a9f618 100644 --- a/src/EventLoop.php +++ b/src/EventLoop.php @@ -8,13 +8,23 @@ interface EventLoop * Waits the resolution of a promise, and returns its value. * You should use this function once for your global result. * - * @return mixed + * @template T + * + * @param Promise $promise + * + * @return T */ public function wait(Promise $promise); /** * Registers a generator in the event loop to execute it asynchronously. * The returned promise will be resolved with the value returned by the generator. + * + * @template T + * + * @param \Generator $generator + * + * @return Promise */ public function async(\Generator $generator): Promise; @@ -28,8 +38,11 @@ public function promiseAll(Promise ...$promises): Promise; * $function applied to each elements of input traversable. * You should use this function each time that you use yield in a foreach loop. * - * @param \Traversable|array $traversable Input elements - * @param callable $function must return a generator from an input value, and an optional key + * @template TKey of array-key + * @template TValue + * + * @param \Traversable|array $traversable Input elements + * @param callable(TValue, TKey): \Generator $function */ public function promiseForeach($traversable, callable $function): Promise; @@ -41,7 +54,11 @@ public function promiseRace(Promise ...$promises): Promise; /** * Creates a promise already resolved with $value. * - * @param mixed $value + * @template T + * + * @param T $value + * + * @return Promise */ public function promiseFulfilled($value): Promise; @@ -52,6 +69,8 @@ public function promiseRejected(\Throwable $throwable): Promise; /** * Creates a promise that will be resolved to null in a future tick of the event loop. + * + * @return Promise */ public function idle(): Promise; @@ -59,6 +78,8 @@ public function idle(): Promise; * Creates a promise that will be resolved to null after a fixed time. * ⚠️ The actual measured delay can be greater if your event loop is busy! * It also can be a little smaller, depending on your event loop (or system clock) accuracy. + * + * @return Promise */ public function delay(int $milliseconds): Promise; @@ -72,6 +93,8 @@ public function deferred(): Deferred; * ⚠️ Error handling (stream connection closed for example) might differ between implementations. * * @param resource $stream + * + * @return Promise */ public function readable($stream): Promise; @@ -80,6 +103,8 @@ public function readable($stream): Promise; * ⚠️ Error handling (stream connection closed for example) might differ between implementations. * * @param resource $stream + * + * @return Promise */ public function writable($stream): Promise; } diff --git a/src/HttpClient.php b/src/HttpClient.php index 54e9dcd..d7879dc 100644 --- a/src/HttpClient.php +++ b/src/HttpClient.php @@ -3,12 +3,15 @@ namespace M6Web\Tornado; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; interface HttpClient { /** * Sends a http request and returns a promise that will be resolved with a * Psr\Http\Message\ResponseInterface + * + * @return Promise */ public function sendRequest(RequestInterface $request): Promise; } diff --git a/src/Promise.php b/src/Promise.php index 39243e8..7405b82 100644 --- a/src/Promise.php +++ b/src/Promise.php @@ -4,6 +4,9 @@ /** * To resolve the value of a promise, you have to yield it from a generator registered in the event loop. + * + * @template-covariant TValue + * @psalm-yield TValue */ interface Promise { diff --git a/tests/Adapter/Guzzle/GuzzleMockWrapper.php b/tests/Adapter/Guzzle/GuzzleMockWrapper.php index e66023b..d2f0696 100644 --- a/tests/Adapter/Guzzle/GuzzleMockWrapper.php +++ b/tests/Adapter/Guzzle/GuzzleMockWrapper.php @@ -10,9 +10,6 @@ final class GuzzleMockWrapper implements GuzzleClientWrapper /** @var \GuzzleHttp\Client */ private $guzzleClient; - /** @var array */ - private $transactions = []; - /** @var int */ public $ticks; diff --git a/tests/EventLoopTest/AsyncTest.php b/tests/EventLoopTest/AsyncTest.php index 9a29f7b..77a7afa 100644 --- a/tests/EventLoopTest/AsyncTest.php +++ b/tests/EventLoopTest/AsyncTest.php @@ -49,6 +49,7 @@ public function testYieldingInvalidValueMayThrowAnError(): void }; $eventLoop = $this->createEventLoop(); + /** @phpstan-ignore-next-line phpstan detects the generator yields a non-promise */ $promise = $eventLoop->async($createGenerator()); $this->expectException(\Error::class); @@ -245,6 +246,8 @@ public function testEventLoopShouldNotThrowInCaseOfExplicitlyRejectedPromise(): $generatorWaitALittle = function () use ($eventLoop) { yield $eventLoop->idle(); yield $eventLoop->idle(); + + return null; }; $unwatchedRejectedPromise = $eventLoop->promiseRejected(new \Exception('Rejected Promise')); diff --git a/tests/EventLoopTest/PromiseForeachTest.php b/tests/EventLoopTest/PromiseForeachTest.php index dfb6e79..a83d48b 100644 --- a/tests/EventLoopTest/PromiseForeachTest.php +++ b/tests/EventLoopTest/PromiseForeachTest.php @@ -46,6 +46,7 @@ public function testPromiseForeachShouldThrowIfCallbackDoesNotReturnGenerator(): $this->expectException(\TypeError::class); $eventLoop->wait( + /* @phpstan-ignore-next-line phpstan detects the callback is invalid */ $eventLoop->promiseForeach([1], $callback) ); }