Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockRetur
class ComplexArray
{
/**
* @return array<string, object|mixed[]>
* @return array<string, \stdClass|array<string, int|string|array<string, string>>>
*/
public function run(): array
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector\Fixture;

final class CoverImplicitKey
{
private static function getExpectedAllOwners(): array
{
return [
[
'key1' => 100,
'key2' => '-25.5%',
],
[
'key3' => 'Yes',
'key4' => 200,
],
];
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector\Fixture;

final class CoverImplicitKey
{
/**
* @return array<int, array<string, string|int>>
*/
private static function getExpectedAllOwners(): array
{
return [
[
'key1' => 100,
'key2' => '-25.5%',
],
[
'key3' => 'Yes',
'key4' => 200,
],
];
}
}

?>
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ public function refactor(Node $node): ?Node

// resolve simple type
$returnedType = $this->getType($soleReturn->expr);

if (! $returnedType instanceof ConstantArrayType) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,12 @@

use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\FloatType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\Privatization\TypeManipulator\TypeNormalizer;
use Rector\StaticTypeMapper\StaticTypeMapper;

final class ConstantArrayTypeGeneralizer
Expand All @@ -32,8 +25,8 @@ final class ConstantArrayTypeGeneralizer
private int $currentNesting = 0;

public function __construct(
private readonly TypeFactory $typeFactory,
private readonly StaticTypeMapper $staticTypeMapper,
private readonly TypeNormalizer $typeNormalizer
) {
}

Expand All @@ -45,7 +38,7 @@ public function generalize(ConstantArrayType $constantArrayType, bool $isFresh =
++$this->currentNesting;
}

$genericKeyType = $this->constantToGenericType($constantArrayType->getKeyType());
$genericKeyType = $this->typeNormalizer->generalizeConstantTypes($constantArrayType->getKeyType());

if ($constantArrayType->getItemType() instanceof NeverType) {
$genericKeyType = new IntegerType();
Expand All @@ -60,7 +53,12 @@ public function generalize(ConstantArrayType $constantArrayType, bool $isFresh =
$genericItemType = $this->generalize($itemType, false);
}
} else {
$genericItemType = $this->constantToGenericType($itemType);
$genericItemType = $this->typeNormalizer->generalizeConstantTypes($itemType);
}

// correct
if ($genericItemType instanceof NeverType) {
$genericItemType = new MixedType();
}

return $this->createArrayGenericTypeNode($genericKeyType, $genericItemType);
Expand All @@ -78,51 +76,4 @@ private function createArrayGenericTypeNode(Type $keyType, Type|GenericTypeNode

return new GenericTypeNode(new IdentifierTypeNode('array'), [$keyDocTypeNode, $itemDocTypeNode]);
}

/**
* Covers constant types too and makes them more generic
*/
private function constantToGenericType(Type $type): Type
{
if ($type->isString()->yes()) {
return new StringType();
}

if ($type->isInteger()->yes()) {
return new IntegerType();
}

if ($type->isBoolean()->yes()) {
return new BooleanType();
}

if ($type->isFloat()->yes()) {
return new FloatType();
}

if ($type->isObject()->yes()) {
return new ObjectWithoutClassType();
}

if ($type instanceof UnionType || $type instanceof IntersectionType) {
$genericComplexTypes = [];
foreach ($type->getTypes() as $splitType) {
$genericComplexTypes[] = $this->constantToGenericType($splitType);
}

$genericComplexTypes = $this->typeFactory->uniquateTypes($genericComplexTypes);
if (count($genericComplexTypes) > 1) {
return new UnionType($genericComplexTypes);
}

return $genericComplexTypes[0];
}

if ($type instanceof ConstantArrayType) {
return new ArrayType(new MixedType(), new MixedType());
}

// unclear
return new MixedType();
}
}
Loading