Skip to content

Commit

Permalink
Fix UnionType description
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 12, 2022
1 parent e491256 commit d05a86b
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 14 deletions.
53 changes: 40 additions & 13 deletions src/Type/UnionType.php
Expand Up @@ -22,9 +22,11 @@
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\Generic\TemplateTypeVariance;
use PHPStan\Type\Generic\TemplateUnionType;
use function array_key_exists;
use function array_map;
use function count;
use function implode;
use function md5;
use function sprintf;
use function strpos;

Expand Down Expand Up @@ -159,24 +161,49 @@ public function equals(Type $type): bool

public function describe(VerbosityLevel $level): string
{
$joinTypes = static function (array $types) use ($level): string {
$getTypeName = static function (Type $type, VerbosityLevel $level): string {
if ($type instanceof ClosureType || $type instanceof CallableType || $type instanceof TemplateUnionType) {
return sprintf('(%s)', $type->describe($level));
} elseif ($type instanceof IntersectionType) {
$intersectionDescription = $type->describe($level);
if (strpos($intersectionDescription, '&') !== false) {
return sprintf('(%s)', $type->describe($level));
}

return $intersectionDescription;
}

return $type->describe($level);
};
$joinTypes = static function (array $types) use ($getTypeName, $level): string {
$typeNames = [];
foreach ($types as $type) {
if ($type instanceof ClosureType || $type instanceof CallableType || $type instanceof TemplateUnionType) {
$typeNames[] = sprintf('(%s)', $type->describe($level));
} elseif ($type instanceof IntersectionType) {
$intersectionDescription = $type->describe($level);
if (strpos($intersectionDescription, '&') !== false) {
$typeNames[] = sprintf('(%s)', $type->describe($level));
} else {
$typeNames[] = $intersectionDescription;
}
} else {
$typeNames[] = $type->describe($level);
$typeName = $getTypeName($type, $level);
$typeNameHash = md5($typeName);
if (!$level->isTypeOnly()) {
$typeNames[$typeNameHash] = [$type, $typeName];
continue;
}

if (!array_key_exists($typeNameHash, $typeNames)) {
$typeNames[$typeNameHash] = [$type, $typeName];
continue;
}

[$otherType] = $typeNames[$typeNameHash];
unset($typeNames[$typeNameHash]);

$newOtherTypeName = $getTypeName($otherType, VerbosityLevel::value());
$newOtherTypeNameHash = md5($newOtherTypeName);

$typeNames[$newOtherTypeNameHash] = [$otherType, $newOtherTypeName];

$typeName = $getTypeName($type, VerbosityLevel::value());
$typeNameHash = md5($typeName);
$typeNames[$typeNameHash] = [$type, $typeName];
}

return implode('|', $typeNames);
return implode('|', array_map(static fn (array $types): string => $types[1], $typeNames));
};

return $level->handle(
Expand Down
5 changes: 5 additions & 0 deletions src/Type/VerbosityLevel.php
Expand Up @@ -55,6 +55,11 @@ public static function cache(): self
return self::create(self::CACHE);
}

public function isTypeOnly(): bool
{
return $this->value === self::TYPE_ONLY;
}

/** @api */
public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acceptedType = null): self
{
Expand Down
10 changes: 9 additions & 1 deletion tests/PHPStan/Type/UnionTypeTest.php
Expand Up @@ -680,6 +680,14 @@ public function dataDescribe(): array
'int|numeric-string',
'int|string',
],
[
TypeCombinator::union(
IntegerRangeType::fromInterval(0, 4),
IntegerRangeType::fromInterval(6, 10),
),
'int<0, 4>|int<6, 10>',
'int<0, 4>|int<6, 10>',
],
];
}

Expand All @@ -692,7 +700,7 @@ public function testDescribe(
string $expectedTypeOnlyDescription,
): void
{
$this->assertSame($expectedValueDescription, $type->describe(VerbosityLevel::precise()));
$this->assertSame($expectedValueDescription, $type->describe(VerbosityLevel::value()));
$this->assertSame($expectedTypeOnlyDescription, $type->describe(VerbosityLevel::typeOnly()));
}

Expand Down

0 comments on commit d05a86b

Please sign in to comment.