Skip to content

POC: Use SimultaneousTypeTraverser in RuleLevelHelper::transformAcceptedType #4210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: 2.1.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions src/Rules/RuleLevelHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\AutowiredParameter;
use PHPStan\DependencyInjection\AutowiredService;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\CallableType;
Expand All @@ -16,6 +17,7 @@
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\NullType;
use PHPStan\Type\SimultaneousTypeTraverser;
use PHPStan\Type\StrictMixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
Expand Down Expand Up @@ -87,20 +89,23 @@
private function transformAcceptedType(Type $acceptingType, Type $acceptedType): array
{
$checkForUnion = $this->checkUnionTypes;
$acceptedType = TypeTraverser::map($acceptedType, function (Type $acceptedType, callable $traverse) use ($acceptingType, &$checkForUnion): Type {
$acceptedType = SimultaneousTypeTraverser::map($acceptedType, $acceptingType, function (Type $acceptedType, Type $acceptingType, callable $traverse) use (&$checkForUnion): Type {
if ($acceptedType instanceof CallableType) {

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.5)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.5, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.4)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.5, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 93 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.
if ($acceptedType->isCommonCallable()) {
return $acceptedType;
}
if (!$acceptingType instanceof ParametersAcceptor) {
return $acceptedType;
}

return new CallableType(
$acceptedType->getParameters(),
$traverse($this->transformCommonType($acceptedType->getReturnType())),
$traverse($this->transformCommonType($acceptedType->getReturnType()), $acceptingType->getReturnType()),
$acceptedType->isVariadic(),
$acceptedType->getTemplateTypeMap(),
$acceptedType->getResolvedTemplateTypeMap(),
$acceptedType->getTemplateTags(),
$acceptedType->isPure(),

Check failure on line 108 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.

Check failure on line 108 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Doing instanceof PHPStan\Type\CallableType is error-prone and deprecated. Use Type::isCallable() and Type::getCallableParametersAcceptors() instead.
);
}

Expand All @@ -109,9 +114,13 @@
return $acceptedType;
}

if (!$acceptingType instanceof ParametersAcceptor) {
return $acceptedType;
}

return new ClosureType(
$acceptedType->getParameters(),
$traverse($this->transformCommonType($acceptedType->getReturnType())),
$traverse($this->transformCommonType($acceptedType->getReturnType()), $acceptingType->getReturnType()),
$acceptedType->isVariadic(),
$acceptedType->getTemplateTypeMap(),
$acceptedType->getResolvedTemplateTypeMap(),
Expand All @@ -127,22 +136,23 @@

if (
!$this->checkNullables
&& !$acceptingType instanceof NullType
&& !$acceptedType instanceof NullType
&& !$acceptedType instanceof BenevolentUnionType
&& !$acceptedType instanceof NullType

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.5)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.5, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.4)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.5, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 140 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.
&& TypeCombinator::containsNull($acceptedType)
&& !TypeCombinator::containsNull($acceptingType)
) {
return $traverse(TypeCombinator::removeNull($acceptedType));
return $traverse(TypeCombinator::removeNull($acceptedType), $acceptingType);
}

if ($this->checkBenevolentUnionTypes) {
if ($acceptedType instanceof BenevolentUnionType) {
$checkForUnion = true;
return $traverse(TypeUtils::toStrictUnion($acceptedType));
return $traverse(TypeUtils::toStrictUnion($acceptedType), $acceptingType);
}
}

return $traverse($this->transformCommonType($acceptedType));
return $traverse($this->transformCommonType($acceptedType), $acceptingType);
});

Check failure on line 155 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

Check failure on line 155 in src/Rules/RuleLevelHelper.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Doing instanceof PHPStan\Type\NullType is error-prone and deprecated. Use Type::isNull() instead.

return [$acceptedType, $checkForUnion];
}
Expand Down
11 changes: 10 additions & 1 deletion tests/PHPStan/Rules/Functions/ClosureReturnTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
class ClosureReturnTypeRuleTest extends RuleTestCase
{

private bool $checkNullables = true;

protected function getRule(): Rule
{
return new ClosureReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper(self::createReflectionProvider(), true, false, true, false, false, false, true)));
return new ClosureReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper(self::createReflectionProvider(), $this->checkNullables, false, true, false, false, false, true)));
}

public function testClosureReturnTypeRule(): void
Expand Down Expand Up @@ -128,6 +130,13 @@ public function testBug7220(): void
$this->analyse([__DIR__ . '/data/bug-7220.php'], []);
}

public function testBug12008(): void
{
$this->checkNullables = false;

$this->analyse([__DIR__ . '/data/bug-12008.php'], []);
}

public function testBugFunctionMethodConstants(): void
{
$this->analyse([__DIR__ . '/data/bug-anonymous-function-method-constant.php'], []);
Expand Down
42 changes: 42 additions & 0 deletions tests/PHPStan/Rules/Functions/data/bug-12008.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php declare(strict_types = 1);

namespace Bug12008;

interface ProductOverview {
public function getId(): ?int;
}

/**
* @template T
*/
readonly class Pagination
{
/**
* @param iterable<T> $records
*/
public function __construct(
public iterable $records,
) {
}
}

class HelloWorld
{
private function respondToApiRequest(Closure|null $data): never {
exit;
}

/**
* @param list<ProductOverview> $products
*/
public function run(array $products): never {
$this->respondToApiRequest(function () use ($products) {
return new Pagination(array_map(
fn (ProductOverview $product) => [
'id' => $product->getId(),
],
$products,
));
});
}
}
Loading