diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/false_and_true.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/false_and_true.php.inc index c6728e3a9ea..8db764d7d68 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/false_and_true.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/false_and_true.php.inc @@ -19,7 +19,7 @@ function FalseAndTrue() namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector\Fixture; /** - * @return array + * @return array */ function FalseAndTrue() { diff --git a/rules/Privatization/TypeManipulator/TypeNormalizer.php b/rules/Privatization/TypeManipulator/TypeNormalizer.php index 4651c7bfe2f..af3bbe8e7e6 100644 --- a/rules/Privatization/TypeManipulator/TypeNormalizer.php +++ b/rules/Privatization/TypeManipulator/TypeNormalizer.php @@ -20,6 +20,7 @@ use PHPStan\Type\TypeTraverser; use PHPStan\Type\UnionType; use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory; +use Rector\NodeTypeResolver\PHPStan\TypeHasher; use Rector\StaticTypeMapper\StaticTypeMapper; final readonly class TypeNormalizer @@ -32,7 +33,8 @@ public function __construct( private TypeFactory $typeFactory, private StaticTypeMapper $staticTypeMapper, - private ArrayTypeLeastCommonDenominatorResolver $arrayTypeLeastCommonDenominatorResolver + private ArrayTypeLeastCommonDenominatorResolver $arrayTypeLeastCommonDenominatorResolver, + private TypeHasher $typeHasher ) { } @@ -94,7 +96,41 @@ public function generalizeConstantTypes(Type $type): Type if ($type instanceof UnionType) { $generalizedUnionedTypes = []; foreach ($type->getTypes() as $unionedType) { - $generalizedUnionedTypes[] = $this->generalizeConstantTypes($unionedType); + $generalizedUnionedType = $this->generalizeConstantTypes($unionedType); + + if ($generalizedUnionedType instanceof ArrayType) { + $keyType = $this->typeHasher->createTypeHash($generalizedUnionedType->getKeyType()); + + foreach ($generalizedUnionedTypes as $key => $existingUnionedType) { + if (! $existingUnionedType instanceof ArrayType) { + continue; + } + + $existingKeyType = $this->typeHasher->createTypeHash( + $existingUnionedType->getKeyType() + ); + + if ($keyType !== $existingKeyType) { + continue; + } + + $uniqueTypes = $this->typeFactory->uniquateTypes( + [$existingUnionedType->getItemType(), $generalizedUnionedType->getItemType()] + ); + + if (count($uniqueTypes) !== 1) { + continue; + } + + $generalizedUnionedTypes[$key] = new ArrayType( + $existingUnionedType->getKeyType(), + $uniqueTypes[0] + ); + continue 2; + } + } + + $generalizedUnionedTypes[] = $generalizedUnionedType; } $uniqueGeneralizedUnionTypes = $this->typeFactory->uniquateTypes($generalizedUnionedTypes);