From 6de3223ab0aceb96986af7d79569c0fc818656af Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Wed, 17 Aug 2022 13:27:31 +0200 Subject: [PATCH 1/5] Improve Makefile a bit --- Makefile | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index e250c70..022c819 100644 --- a/Makefile +++ b/Makefile @@ -3,16 +3,24 @@ all: deps test deps: - docker run -it --rm -v ${PWD}:/app -w /app composer update --prefer-dist --verbose --no-interaction --optimize-autoloader + docker run -it --rm -v ${PWD}:/app -w /app composer update --prefer-dist --verbose --no-interaction test: - docker run -it --rm -v ${PWD}:/app -w /app composer run-script test + $(MAKE) phpunit + $(MAKE) phpstan + $(MAKE) fmt-check phpstan: - docker run -it --rm -v ${PWD}:/app -w /app composer run-script phpstan + docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php -d error_reporting=-1 -d memory_limit=-1 bin/phpstan --ansi analyse + +phpstan-clear-cache: + docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php -d error_reporting=-1 -d memory_limit=-1 bin/phpstan --ansi clear-result-cache + +phpunit: + docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php -d error_reporting=-1 bin/phpunit --colors=always -c phpunit.xml fmt-check: - docker run -it --rm -v ${PWD}:/app -w /app composer run-script phpcs + docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php bin/phpcs --standard=./ruleset.xml --extensions=php --tab-width=4 -sp ./src ./tests fmt: - docker run -it --rm -v ${PWD}:/app -w /app composer run-script phpcbf + docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php bin/phpcbf --standard=./ruleset.xml --extensions=php --tab-width=4 -sp ./src ./tests From 82ed3e0156c94f8befd23f6947f0b23277b7091f Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Wed, 17 Aug 2022 13:27:56 +0200 Subject: [PATCH 2/5] Upgrade dependencies --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ff46fd4..ed9a136 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ ], "require": { "php": ">=7.3|^8.0", - "phpstan/phpstan": "^0.12|^1.0" + "phpstan/phpstan": "^1.0" }, "require-dev": { "roave/security-advisories": "dev-latest", @@ -19,7 +19,7 @@ "phpunit/phpunit": "^9.4.2", "slevomat/coding-standard": "^6.4.1", "squizlabs/php_codesniffer": "^3.5.0", - "bonami/collections": "^0.3.8" + "bonami/collections": "^0.4.5" }, "config": { "bin-dir": "bin", From 884c32a0e9aa8ffb1db7f3ce885f608a1fc4d6d3 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Wed, 17 Aug 2022 13:28:28 +0200 Subject: [PATCH 3/5] Drop tests for deprecated methods --- extension.neon | 2 +- tests/Bonami/Collection/Phpstan/ArrayListTest.php | 15 --------------- tests/Bonami/Collection/Phpstan/LazyListTest.php | 11 ----------- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/extension.neon b/extension.neon index 8b236ae..2d5c59b 100644 --- a/extension.neon +++ b/extension.neon @@ -25,7 +25,7 @@ services: - phpstan.broker.dynamicMethodReturnTypeExtension - class: Bonami\Collection\Phpstan\LateStaticBindingStaticMethodReturnTypeExtension - factory: Bonami\Collection\Phpstan\LateStaticBindingStaticMethodReturnTypeExtension::forMethods('Bonami\Collection\LazyList', ['fill', 'fromEmpty', 'fromArray', 'fromIterable', 'of']) + factory: Bonami\Collection\Phpstan\LateStaticBindingStaticMethodReturnTypeExtension::forMethods('Bonami\Collection\LazyList', ['fill', 'fromEmpty', 'fromIterable', 'of']) tags: - phpstan.broker.dynamicStaticMethodReturnTypeExtension - diff --git a/tests/Bonami/Collection/Phpstan/ArrayListTest.php b/tests/Bonami/Collection/Phpstan/ArrayListTest.php index 0070dad..c785888 100644 --- a/tests/Bonami/Collection/Phpstan/ArrayListTest.php +++ b/tests/Bonami/Collection/Phpstan/ArrayListTest.php @@ -140,21 +140,6 @@ public function testSliceReturnType(): void self::assertInstanceOf(FooArrayList::class, $concreteList); } - public function testWithoutNullsReturnType(): void - { - /** @var iterable $iterable */ - $iterable = [new Foo(), null]; - /** @var ArrayList $list */ - $list = ArrayList::fromIterable($iterable); - $genericList = $list->withoutNulls(); - $this->requireArrayListOfFoo($genericList->withoutNulls()); - self::assertInstanceOf(ArrayList::class, $genericList); - - $concreteList = FooArrayList::fromIterable($genericList)->withoutNulls(); - $this->requireFooList($concreteList->withoutNulls()); - self::assertInstanceOf(FooArrayList::class, $concreteList); - } - public function testMinusReturnType(): void { $genericList = ArrayList::fromIterable([new Foo()])->minus([new Foo()]); diff --git a/tests/Bonami/Collection/Phpstan/LazyListTest.php b/tests/Bonami/Collection/Phpstan/LazyListTest.php index d668a32..2fa3beb 100644 --- a/tests/Bonami/Collection/Phpstan/LazyListTest.php +++ b/tests/Bonami/Collection/Phpstan/LazyListTest.php @@ -32,17 +32,6 @@ public function testFromEmptyReturnType(): void self::assertInstanceOf(FooLazyList::class, $concreteList); } - public function testFromArrayReturnType(): void - { - $genericList = LazyList::fromArray(); - $this->requireLazyListOfFoo($genericList); - self::assertInstanceOf(LazyList::class, $genericList); - - $concreteList = FooLazyList::fromArray([new Foo()]); - $this->requireFooList($concreteList); - self::assertInstanceOf(FooLazyList::class, $concreteList); - } - public function testFromIterableReturnType(): void { $genericList = LazyList::fromIterable([new Foo()]); From d3361487665be4d57d1e36f5cbcb3c10d8289935 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Wed, 17 Aug 2022 13:29:53 +0200 Subject: [PATCH 4/5] Explicitely annotate types Those cannot be infered --- tests/Bonami/Collection/Phpstan/ArrayListTest.php | 3 +++ tests/Bonami/Collection/Phpstan/LazyListTest.php | 1 + tests/Bonami/Collection/Phpstan/MapTest.php | 1 + 3 files changed, 5 insertions(+) diff --git a/tests/Bonami/Collection/Phpstan/ArrayListTest.php b/tests/Bonami/Collection/Phpstan/ArrayListTest.php index c785888..c4c50fe 100644 --- a/tests/Bonami/Collection/Phpstan/ArrayListTest.php +++ b/tests/Bonami/Collection/Phpstan/ArrayListTest.php @@ -8,10 +8,13 @@ use Bonami\Collection\Map; use PHPUnit\Framework\TestCase; +use function PHPStan\dumpType; + class ArrayListTest extends TestCase { public function testFromEmptyReturnType(): void { + /** @var ArrayList $genericList */ $genericList = ArrayList::fromEmpty(); $this->requireArrayListOfFoo($genericList); self::assertInstanceOf(ArrayList::class, $genericList); diff --git a/tests/Bonami/Collection/Phpstan/LazyListTest.php b/tests/Bonami/Collection/Phpstan/LazyListTest.php index 2fa3beb..23789be 100644 --- a/tests/Bonami/Collection/Phpstan/LazyListTest.php +++ b/tests/Bonami/Collection/Phpstan/LazyListTest.php @@ -23,6 +23,7 @@ public function testFillReturnType(): void public function testFromEmptyReturnType(): void { + /** @var LazyList $genericList */ $genericList = LazyList::fromEmpty(); $this->requireLazyListOfFoo($genericList); self::assertInstanceOf(LazyList::class, $genericList); diff --git a/tests/Bonami/Collection/Phpstan/MapTest.php b/tests/Bonami/Collection/Phpstan/MapTest.php index fb3547e..a2190a1 100644 --- a/tests/Bonami/Collection/Phpstan/MapTest.php +++ b/tests/Bonami/Collection/Phpstan/MapTest.php @@ -33,6 +33,7 @@ public function testFromOnlyReturnType(): void public function testFromEmptyReturnType(): void { + /** @var Map $genericList */ $genericList = Map::fromEmpty(); $this->requireMapOfFoo($genericList); self::assertInstanceOf(Map::class, $genericList); From b6160ecfa808a16c93a4b3a4e94f700419a9ac68 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Wed, 17 Aug 2022 13:30:17 +0200 Subject: [PATCH 5/5] Fix default logic for base classes This way it correctly falls back on default implementation for base classes. --- ...BindingStaticMethodReturnTypeExtension.php | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/Bonami/Collection/Phpstan/LateStaticBindingStaticMethodReturnTypeExtension.php b/src/Bonami/Collection/Phpstan/LateStaticBindingStaticMethodReturnTypeExtension.php index 92d6ca5..9e50026 100644 --- a/src/Bonami/Collection/Phpstan/LateStaticBindingStaticMethodReturnTypeExtension.php +++ b/src/Bonami/Collection/Phpstan/LateStaticBindingStaticMethodReturnTypeExtension.php @@ -4,17 +4,14 @@ namespace Bonami\Collection\Phpstan; -use PhpParser\Node\Arg; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; -use PHPStan\Type\ConstantType; +use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\DynamicStaticMethodReturnTypeExtension; -use PHPStan\Type\GeneralizePrecision; use PHPStan\Type\Generic\GenericClassStringType; -use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; @@ -60,7 +57,6 @@ public function getTypeFromStaticMethodCall( StaticCall $methodCall, Scope $scope ): Type { - $declaringClassReflection = $methodReflection->getDeclaringClass(); $calledClassExpr = $methodCall->class; if ($calledClassExpr instanceof PropertyFetch) { $type = $scope->getType($calledClassExpr); @@ -78,26 +74,11 @@ public function getTypeFromStaticMethodCall( ); if ($calledOnTopLevelParent) { - if ($methodReflection->getName() === 'of') { - $arg = $methodCall->getArgs()[0]; - assert($arg instanceof Arg); - - $type = $scope->getType($arg->value); - $widend = $type instanceof ConstantType - ? $type->generalize(GeneralizePrecision::lessSpecific()) - : $type; - - return new GenericObjectType( - $declaringClassReflection->getName(), - [$widend] - ); - } - return new GenericObjectType( - $declaringClassReflection->getName(), - $declaringClassReflection->typeMapToList( - $declaringClassReflection->getTemplateTypeMap()->resolveToBounds() - ) - ); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants() + )->getReturnType(); } $calledInsideExtendedClass = $calledClassExprString === 'self';