Skip to content

Commit

Permalink
[TypeDeclaration] Allow union with closure type on property on TypedP…
Browse files Browse the repository at this point in the history
…ropertyFromAssignsRector (#6717)
  • Loading branch information
samsonasik authored Feb 5, 2025
1 parent 7f91068 commit a4c489e
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

class SkipUnionCallable
{
private $property;

public function run(callable $prop): void
{
if (rand(0, 1)) {
$this->property = $prop;
} else {
$this->property = false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

class UnionClosure
{
private $property;

public function run(): void
{
if (rand(0, 1)) {
$this->property = function (): void {
};
} else {
$this->property = false;
}
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

class UnionClosure
{
private \Closure|bool|null $property = null;

public function run(): void
{
if (rand(0, 1)) {
$this->property = function (): void {
};
} else {
$this->property = false;
}
}
}

?>
2 changes: 1 addition & 1 deletion src/NodeAnalyzer/PropertyAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function hasForbiddenType(Property $property): bool
return false;
}

private function isForbiddenType(Type $type): bool
public function isForbiddenType(Type $type): bool
{
if ($type instanceof NonExistingObjectType) {
return true;
Expand Down
17 changes: 11 additions & 6 deletions src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,20 @@ public function mapToPhpParserNode(Type $type, string $typeKind): ?Node
return new FullyQualified('Closure');
}

if ($typeKind !== TypeKind::RETURN) {
return null;
// ref https://3v4l.org/nUreN#v7.0.0
if ($typeKind === TypeKind::RETURN && $this->phpVersionProvider->isAtLeastPhpVersion(
PhpVersionFeature::ANONYMOUS_FUNCTION_RETURN_TYPE
)) {
return new FullyQualified('Closure');
}

// ref https://3v4l.org/nUreN#v7.0.0
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::ANONYMOUS_FUNCTION_RETURN_TYPE)) {
return null;
// ref https://3v4l.org/ruh5g#v8.0.0
if ($typeKind === TypeKind::UNION && $this->phpVersionProvider->isAtLeastPhpVersion(
PhpVersionFeature::UNION_TYPES
)) {
return new FullyQualified('Closure');
}

return new FullyQualified('Closure');
return null;
}
}
4 changes: 3 additions & 1 deletion src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode;
use Rector\NodeAnalyzer\PropertyAnalyzer;
use Rector\Php\PhpVersionProvider;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
Expand All @@ -33,6 +34,7 @@ final class UnionTypeMapper implements TypeMapperInterface

public function __construct(
private readonly PhpVersionProvider $phpVersionProvider,
private readonly PropertyAnalyzer $propertyAnalyzer
) {
}

Expand Down Expand Up @@ -184,7 +186,7 @@ private function matchPhpParserUnionType(UnionType $unionType, string $typeKind)
}

// special callable type only not allowed on property
if ($typeKind === TypeKind::PROPERTY && $unionedType->isCallable()->yes()) {
if ($typeKind === TypeKind::PROPERTY && $this->propertyAnalyzer->isForbiddenType($unionedType)) {
return null;
}

Expand Down

0 comments on commit a4c489e

Please sign in to comment.