From e24c4304a4b1349c2a83151a692cec0c10579f60 Mon Sep 17 00:00:00 2001
From: Alexey Kopytko <alexey@kopytko.com>
Date: Tue, 24 Oct 2023 09:25:28 +0900
Subject: [PATCH] Introduce typed properties (#16)

---
 .phan/config.php              |  2 +-
 .php-cs-fixer.dist.php        | 51 ++++++++++++++++++++---------------
 Makefile                      |  1 +
 psalm.xml                     |  4 +++
 src/Deferred.php              | 16 +++++------
 src/Immediate.php             |  3 ++-
 tests/DeferredTest.php        | 10 ++++---
 tests/Examples/Calculator.php |  3 ++-
 tests/ExamplesTest.php        | 14 +++++-----
 9 files changed, 61 insertions(+), 43 deletions(-)

diff --git a/.phan/config.php b/.phan/config.php
index 53c8d56..c7b633e 100644
--- a/.phan/config.php
+++ b/.phan/config.php
@@ -3,7 +3,7 @@
 use Phan\Issue;
 
 return [
-    'target_php_version' => '7.1',
+    'target_php_version' => '7.4',
     'backward_compatibility_checks' => false,
     'exclude_analysis_directory_list' => [
         'vendor/',
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index acd95c8..fca2ed5 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -18,40 +18,49 @@
 declare(strict_types=1);
 
 $header = <<<'EOF'
-Copyright 2020 Alexey Kopytko <alexey@kopytko.com>
+    Copyright 2020 Alexey Kopytko <alexey@kopytko.com>
 
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
 
-http://www.apache.org/licenses/LICENSE-2.0
+    http://www.apache.org/licenses/LICENSE-2.0
 
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-EOF;
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+    EOF;
 
 $config = new PhpCsFixer\Config();
 $config
     ->setRiskyAllowed(true)
     ->setRules([
         'header_comment' => ['comment_type' => 'PHPDoc', 'header' => $header, 'separate' => 'bottom', 'location' => 'after_open'],
+        '@PER-CS' => true,
+        '@PER-CS:risky' => true,
 
-        '@Symfony:risky' => true,
-        '@PHP71Migration:risky' => true,
-        '@PHPUnit75Migration:risky' => true,
-        '@PhpCsFixer' => true,
-        '@PhpCsFixer:risky' => true,
+        '@PHPUnit100Migration:risky' => true,
+        '@PHP74Migration' => true,
+
+        'native_constant_invocation' => [
+            'strict' => false,
+            'scope' => 'namespaced',
+        ],
+        'native_function_invocation' => [
+            'include' => ['@internal'],
+            'scope' => 'namespaced',
+        ],
+        'global_namespace_import' => [
+            'import_classes' => true,
+            'import_constants' => true,
+            'import_functions' => true,
+        ],
 
-        'ordered_class_elements' => false,
-        'phpdoc_to_comment' => false,
         'strict_comparison' => true,
-        'comment_to_phpdoc' => true,
-        'native_function_invocation' => ['include' => ['@internal'], 'scope' => 'namespaced'],
-        'php_unit_test_case_static_method_calls' => false,
         'yoda_style' => true,
+        'array_indentation' => true,
     ])
     ->setFinder(
         PhpCsFixer\Finder::create()
diff --git a/Makefile b/Makefile
index 842f2a6..766bb2f 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,7 @@ PHPUNIT=vendor/bin/phpunit
 PHPUNIT_COVERAGE_CLOVER=--coverage-clover=build/logs/clover.xml
 PHPUNIT_GROUP=default
 PHPUNIT_ARGS=--coverage-xml=build/logs/coverage-xml --log-junit=build/logs/junit.xml $(PHPUNIT_COVERAGE_CLOVER)
+export XDEBUG_MODE=coverage
 
 # Phan
 PHAN=vendor/bin/phan
diff --git a/psalm.xml b/psalm.xml
index d9f3e81..0a6116f 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -10,4 +10,8 @@
         <directory name="src" />
         <directory name="tests/Examples" />
     </projectFiles>
+
+    <issueHandlers>
+        <PropertyNotSetInConstructor errorLevel="suppress" />
+    </issueHandlers>
 </psalm>
diff --git a/src/Deferred.php b/src/Deferred.php
index 03a5a26..0ac0417 100644
--- a/src/Deferred.php
+++ b/src/Deferred.php
@@ -19,6 +19,8 @@
 
 namespace Later;
 
+use Throwable;
+
 /**
  * Deferred: a wrapper object.
  *
@@ -26,26 +28,22 @@
  *
  * @template-implements Interfaces\Deferred<T>
  *
- * @psalm-suppress PropertyNotSetInConstructor
- *
  * @internal
+ * @final
  */
-final class Deferred implements Interfaces\Deferred
+class Deferred implements Interfaces\Deferred
 {
     /**
      * @var ?iterable<T>
      */
-    private $input;
+    private ?iterable $input;
 
     /**
      * @var T
      */
     private $output;
 
-    /**
-     * @var ?\Throwable
-     */
-    private $error;
+    private ?Throwable $error;
 
     /**
      * @param iterable<T> $input
@@ -75,7 +73,7 @@ public function get()
 
                 break;
             }
-        } catch (\Throwable $e) {
+        } catch (Throwable $e) {
             $this->error = $e;
 
             throw $e;
diff --git a/src/Immediate.php b/src/Immediate.php
index 0dc39d3..b1fc49c 100644
--- a/src/Immediate.php
+++ b/src/Immediate.php
@@ -27,8 +27,9 @@
  * @template-implements Interfaces\Deferred<T>
  *
  * @internal
+ * @final
  */
-final class Immediate implements Interfaces\Deferred
+class Immediate implements Interfaces\Deferred
 {
     /**
      * @var T
diff --git a/tests/DeferredTest.php b/tests/DeferredTest.php
index 946cc7a..faffebe 100644
--- a/tests/DeferredTest.php
+++ b/tests/DeferredTest.php
@@ -20,6 +20,8 @@
 namespace Tests\Later;
 
 use Later\Deferred;
+use ReflectionClass;
+use InvalidArgumentException;
 
 /**
  * @covers \Later\Deferred
@@ -93,18 +95,18 @@ public function testThrowsSame(): void
         try {
             $this->assertDeferredSame(1, $later);
             $this->fail('Should have thrown');
-        } catch (\InvalidArgumentException $e) {
+        } catch (InvalidArgumentException $e) {
             $this->assertSame(__CLASS__, $e->getMessage());
         }
 
         try {
             $this->assertDeferredSame(1, $later);
-        } catch (\InvalidArgumentException $e2) {
+        } catch (InvalidArgumentException $e2) {
             $this->assertSame($e, $e2);
         }
 
         // Make sure the input is discarded
-        $reflectionClass = new \ReflectionClass($later);
+        $reflectionClass = new ReflectionClass($later);
         $property = $reflectionClass->getProperty('input');
         $property->setAccessible(true);
         $this->assertNull($property->getValue($later));
@@ -116,7 +118,7 @@ public function testThrowsSame(): void
     private function generatorThrows(bool $throw = false): iterable
     {
         if ($throw) {
-            throw new \InvalidArgumentException(__CLASS__);
+            throw new InvalidArgumentException(__CLASS__);
         }
 
         yield 1;
diff --git a/tests/Examples/Calculator.php b/tests/Examples/Calculator.php
index 4b3573f..5544c9d 100644
--- a/tests/Examples/Calculator.php
+++ b/tests/Examples/Calculator.php
@@ -22,6 +22,7 @@
 use Later\Interfaces\Deferred;
 
 use function Later\lazy;
+use function usleep;
 
 /**
  * An object which used to do a lot all at once.
@@ -44,7 +45,7 @@ private function makeDependency(int $number)
         $factorial = 1;
 
         for ($i = 1; $i <= $number; ++$i) {
-            \usleep(100);
+            usleep(100);
             $factorial *= $i;
         }
 
diff --git a/tests/ExamplesTest.php b/tests/ExamplesTest.php
index 9a8e421..df0a7fd 100644
--- a/tests/ExamplesTest.php
+++ b/tests/ExamplesTest.php
@@ -23,6 +23,8 @@
 use Tests\Later\Examples\DeepThought;
 use Tests\Later\Examples\HyperIntelligentMice;
 
+use function microtime;
+
 /**
  * @coversNothing
  *
@@ -75,21 +77,21 @@ public function testMockCalledOnce(): void
 
     public function testCalculator(): void
     {
-        $start = \microtime(true);
+        $start = microtime(true);
         $calculator = new Calculator(10);
-        $initTime = \microtime(true) - $start;
+        $initTime = microtime(true) - $start;
 
-        $start = \microtime(true);
+        $start = microtime(true);
         $result = (string) $calculator;
-        $calcTime = \microtime(true) - $start;
+        $calcTime = microtime(true) - $start;
 
         $this->assertStringStartsWith('3628800', $result);
 
         $this->assertGreaterThan($initTime, $calcTime);
 
-        $start = \microtime(true);
+        $start = microtime(true);
         $result = (string) $calculator;
-        $nextCalcTime = \microtime(true) - $start;
+        $nextCalcTime = microtime(true) - $start;
 
         $this->assertLessThan($calcTime, $nextCalcTime);
     }