Skip to content

Commit

Permalink
Solve duplicates in UnionType description
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet committed Mar 18, 2024
1 parent 2d4a799 commit 8c64537
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/Type/UnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use PHPStan\Type\Generic\TemplateTypeVariance;
use PHPStan\Type\Generic\TemplateUnionType;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use function array_diff_assoc;
use function array_fill_keys;
use function array_map;
use function array_merge;
use function array_slice;
Expand Down Expand Up @@ -293,6 +295,22 @@ public function describe(VerbosityLevel $level): string
}
}

if ($level->isPrecise()) {
$duplicates = array_diff_assoc($typeNames, array_unique($typeNames));
if (count($duplicates) > 0) {
$indexByDuplicate = array_fill_keys($duplicates, 0);
foreach ($typeNames as $key => $typeName) {
if (!isset($indexByDuplicate[$typeName])) {
continue;
}

$typeNames[$key] = $typeName . '#' . ++$indexByDuplicate[$typeName];
}
}
} else {
$typeNames = array_unique($typeNames);
}

if (count($typeNames) > 1024) {
return implode('|', array_slice($typeNames, 0, 1024)) . "|\u{2026}";
}
Expand Down
5 changes: 5 additions & 0 deletions src/Type/VerbosityLevel.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public function isValue(): bool
return $this->value === self::VALUE;
}

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

/** @api */
public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acceptedType = null): self
{
Expand Down
22 changes: 22 additions & 0 deletions tests/PHPStan/Type/UnionTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -717,11 +717,13 @@ public function dataDescribe(): array
new UnionType([new IntegerType(), new StringType()]),
'int|string',
'int|string',
'int|string',
],
[
new UnionType([new IntegerType(), new StringType(), new NullType()]),
'int|string|null',
'int|string|null',
'int|string|null',
],
[
new UnionType([
Expand All @@ -742,6 +744,7 @@ public function dataDescribe(): array
new ConstantStringType('1'),
]),
"1|2|2.2|10|'1'|'10'|'10aaa'|'11aaa'|'1aaa'|'2'|'2aaa'|'foo'|stdClass|true|null",
"1|2|2.2|10|'1'|'10'|'10aaa'|'11aaa'|'1aaa'|'2'|'2aaa'|'foo'|stdClass|true|null",
'float|int|stdClass|string|true|null',
],
[
Expand All @@ -763,6 +766,7 @@ public function dataDescribe(): array
new ConstantStringType('aaa'),
),
'\'aaa\'|array{a: int, b: float}|array{a: string, b: bool}',
'\'aaa\'|array{a: int, b: float}|array{a: string, b: bool}',
'array<string, bool|float|int|string>|string',
],
[
Expand All @@ -784,6 +788,7 @@ public function dataDescribe(): array
new ConstantStringType('aaa'),
),
'\'aaa\'|array{a: string, b: bool}|array{b: int, c: float}',
'\'aaa\'|array{a: string, b: bool}|array{b: int, c: float}',
'array<string, bool|float|int|string>|string',
],
[
Expand All @@ -805,6 +810,7 @@ public function dataDescribe(): array
new ConstantStringType('aaa'),
),
'\'aaa\'|array{a: string, b: bool}|array{c: int, d: float}',
'\'aaa\'|array{a: string, b: bool}|array{c: int, d: float}',
'array<string, bool|float|int|string>|string',
],
[
Expand All @@ -825,6 +831,7 @@ public function dataDescribe(): array
]),
),
'array{int, bool, float}|array{string}',
'array{int, bool, float}|array{string}',
'array<int, bool|float|int|string>',
],
[
Expand All @@ -837,6 +844,7 @@ public function dataDescribe(): array
]),
),
'array{}|array{foooo: \'barrr\'}',
'array{}|array{foooo: \'barrr\'}',
'array<string, string>',
],
[
Expand All @@ -848,6 +856,7 @@ public function dataDescribe(): array
]),
),
'int|numeric-string',
'int|numeric-string',
'int|string',
],
[
Expand All @@ -857,6 +866,7 @@ public function dataDescribe(): array
),
'int<0, 4>|int<6, 10>',
'int<0, 4>|int<6, 10>',
'int<0, 4>|int<6, 10>',
],
[
TypeCombinator::union(
Expand All @@ -868,6 +878,7 @@ public function dataDescribe(): array
),
new NullType(),
),
'TFoo of int (class foo, parameter)|null',
'(TFoo of int)|null',
'(TFoo of int)|null',
],
Expand All @@ -881,6 +892,7 @@ public function dataDescribe(): array
),
new GenericClassStringType(new ObjectType('Abc')),
),
'class-string<Abc>|TFoo of int (class foo, parameter)',
'class-string<Abc>|TFoo of int',
'class-string<Abc>|TFoo of int',
],
Expand All @@ -894,6 +906,7 @@ public function dataDescribe(): array
),
new NullType(),
),
'TFoo (class foo, parameter)|null',
'TFoo|null',
'TFoo|null',
],
Expand All @@ -912,9 +925,16 @@ public function dataDescribe(): array
),
new NullType(),
),
'TFoo of TBar (class foo, parameter) (class foo, parameter)|null',
'(TFoo of TBar)|null',
'(TFoo of TBar)|null',
],
[
new UnionType([new ObjectType('Foo'), new ObjectType('Foo')]),
'Foo#1|Foo#2',
'Foo',
'Foo',
],
];
}

Expand All @@ -923,10 +943,12 @@ public function dataDescribe(): array
*/
public function testDescribe(
Type $type,
string $expectedPreciseDescription,
string $expectedValueDescription,
string $expectedTypeOnlyDescription,
): void
{
$this->assertSame($expectedPreciseDescription, $type->describe(VerbosityLevel::precise()));
$this->assertSame($expectedValueDescription, $type->describe(VerbosityLevel::value()));
$this->assertSame($expectedTypeOnlyDescription, $type->describe(VerbosityLevel::typeOnly()));
}
Expand Down

0 comments on commit 8c64537

Please sign in to comment.