Skip to content

Commit

Permalink
simplify
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Dec 25, 2022
1 parent 02f42ae commit 1543793
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 53 deletions.
28 changes: 16 additions & 12 deletions src/Type/IntersectionType.php
Expand Up @@ -27,7 +27,6 @@
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use function array_map;
use function array_merge;
use function count;
use function implode;
use function in_array;
Expand Down Expand Up @@ -94,47 +93,52 @@ public function inferTemplateTypesOn(Type $templateType): TemplateTypeMap
return $types;
}

/**
* @return string[]
*/
public function getReferencedClasses(): array
{
$classes = [];
foreach ($this->types as $type) {
$classes[] = $type->getReferencedClasses();
foreach ($type->getReferencedClasses() as $className) {
$classes[] = $className;
}
}

return array_merge(...$classes);
return $classes;
}

public function getArrays(): array
{
$arrays = [];
foreach ($this->types as $type) {
$arrays[] = $type->getArrays();
foreach ($type->getArrays() as $array) {
$arrays[] = $array;
}
}

return array_merge(...$arrays);
return $arrays;
}

public function getConstantArrays(): array
{
$constantArrays = [];
foreach ($this->types as $type) {
$constantArrays[] = $type->getConstantArrays();
foreach ($type->getConstantArrays() as $constantArray) {
$constantArrays[] = $constantArray;
}
}

return array_merge(...$constantArrays);
return $constantArrays;
}

public function getConstantStrings(): array
{
$strings = [];
foreach ($this->types as $type) {
$strings[] = $type->getConstantStrings();
foreach ($type->getConstantStrings() as $string) {
$strings[] = $string;
}
}

return array_merge(...$strings);
return $strings;
}

public function accepts(Type $otherType, bool $strictTypes): TrinaryLogic
Expand Down
69 changes: 28 additions & 41 deletions src/Type/UnionType.php
Expand Up @@ -16,9 +16,7 @@
use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\Generic\GenericClassStringType;
use PHPStan\Type\Generic\TemplateMixedType;
use PHPStan\Type\Generic\TemplateType;
Expand All @@ -27,7 +25,6 @@
use PHPStan\Type\Generic\TemplateUnionType;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use function array_map;
use function array_merge;
use function count;
use function implode;
use function sprintf;
Expand Down Expand Up @@ -80,24 +77,6 @@ public function getTypes(): array
return $this->types;
}

/**
* @param class-string<Type> $typeClass
* @return list<Type>
*/
private function getTypesOfClass(string $typeClass): array
{
$matchingTypes = [];
foreach ($this->getTypes() as $innerType) {
if (!$innerType instanceof $typeClass) {
return [];
}

$matchingTypes[] = $innerType;
}

return $matchingTypes;
}

public function isNormalized(): bool
{
return $this->normalized;
Expand Down Expand Up @@ -125,52 +104,60 @@ public function getReferencedClasses(): array
{
$classes = [];
foreach ($this->types as $type) {
$classes[] = $type->getReferencedClasses();
foreach ($type->getReferencedClasses() as $className) {
$classes[] = $className;
}
}

return array_merge(...$classes);
return $classes;
}

public function getArrays(): array
{
$arrays = [];
foreach ($this->types as $type) {
$arrays[] = $type->getArrays();
}

if ($arrays === []) {
return [];
foreach ($type->getArrays() as $array) {
$arrays[] = $array;
}
}

return array_merge(...$arrays);
return $arrays;
}

public function getConstantArrays(): array
{
$constantArrays = [];
foreach ($this->getTypesOfClass(ConstantArrayType::class) as $type) {
$constantArrays[] = $type->getConstantArrays();
}
foreach ($this->types as $type) {
$typeAsConstantArrays = $type->getConstantArrays();

if ($constantArrays === []) {
return [];
if ($typeAsConstantArrays === []) {
return [];
}

foreach ($typeAsConstantArrays as $constantArray) {
$constantArrays[] = $constantArray;
}
}

return array_merge(...$constantArrays);
return $constantArrays;
}

public function getConstantStrings(): array
{
$strings = [];
foreach ($this->getTypesOfClass(ConstantStringType::class) as $type) {
$strings[] = $type->getConstantStrings();
}
foreach ($this->types as $type) {
$constantStrings = $type->getConstantStrings();

if ($constantStrings === []) {
return [];
}

if ($strings === []) {
return [];
foreach ($constantStrings as $string) {
$strings[] = $string;
}
}

return array_merge(...$strings);
return $strings;
}

public function accepts(Type $type, bool $strictTypes): TrinaryLogic
Expand Down
23 changes: 23 additions & 0 deletions test.php
@@ -0,0 +1,23 @@
<?php declare(strict_types = 1);

use function PHPStan\Testing\assertType;

class Foo {}
class Bar {}

class HelloWorld
{
/**
* @param array{1?: ?int, 2?: string} $a1
* @param array{Foo, Bar} $a2
* @param array{1?: int, 2?: string}|int $a3
*/
public function constantArrayUnion($a1, $a2, $a3, array $a4): void
{
if ($a1 === []) {
return;
}
// assertType('array{0: Foo, 1: Bar|int|null, 2?: string} ', $a1 + $a2);
assertType('array{}', $a3 + $a4);
}
}
130 changes: 130 additions & 0 deletions tests/PHPStan/Type/UnionTypeTest.php
Expand Up @@ -10,6 +10,7 @@
use PHPStan\Reflection\PassedByReference;
use PHPStan\Testing\PHPStanTestCase;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Accessory\AccessoryLiteralStringType;
use PHPStan\Type\Accessory\AccessoryNumericStringType;
use PHPStan\Type\Accessory\HasMethodType;
use PHPStan\Type\Accessory\HasOffsetType;
Expand All @@ -25,6 +26,7 @@
use PHPStan\Type\Generic\TemplateTypeFactory;
use PHPStan\Type\Generic\TemplateTypeScope;
use PHPStan\Type\Generic\TemplateTypeVariance;
use RecursionCallable\Foo;
use stdClass;
use function array_merge;
use function array_reverse;
Expand Down Expand Up @@ -1217,4 +1219,132 @@ public function testSorting(): void
);
}

/**
* @dataProvider dataGetConstantArrays
* @param Type[] $types
* @param list<string> $expectedDescriptions
*/
public function testGetConstantArrays(
array $types,
array $expectedDescriptions,
): void
{
$unionType = TypeCombinator::union(...$types);
$constantArrays = $unionType->getConstantArrays();

$actualDescriptions = [];
foreach ($constantArrays as $constantArray) {
$actualDescriptions[] = $constantArray->describe(VerbosityLevel::precise());
}

$this->assertSame($expectedDescriptions, $actualDescriptions);
}

public function dataGetConstantArrays(): iterable
{
yield from [
[
[
TypeCombinator::intersect(
new ConstantArrayType(
[new ConstantIntegerType(1), new ConstantIntegerType(2)],
[new IntegerType(), new StringType()],
2,
[0, 1],
),
new NonEmptyArrayType(),
),
new ConstantArrayType(
[new ConstantIntegerType(0), new ConstantIntegerType(1)],
[new ObjectType(Foo::class), new ObjectType(stdClass::class)],
2,
),
],
[
'array{1?: int, 2?: string}',
'array{RecursionCallable\Foo, stdClass}',
],
],
[
[
TypeCombinator::intersect(
new ConstantArrayType(
[new ConstantIntegerType(1), new ConstantIntegerType(2)],
[new IntegerType(), new StringType()],
2,
[0, 1],
),
),
new IntegerType(),
],
[],
],
];
}

/**
* @dataProvider dataGetConstantStrings
* @param list<string> $expectedDescriptions
*/
public function testGetConstantStrings(
Type $unionType,
array $expectedDescriptions,
): void
{
$constantStrings = $unionType->getConstantStrings();

$actualDescriptions = [];
foreach ($constantStrings as $constantString) {
$actualDescriptions[] = $constantString->describe(VerbosityLevel::precise());
}

$this->assertSame($expectedDescriptions, $actualDescriptions);
}

public function dataGetConstantStrings(): iterable
{
yield from [
[
TypeCombinator::union(
new ConstantStringType('hello'),
new ConstantStringType('world'),
),
[
"'hello'",
"'world'",
],
],
[
TypeCombinator::union(
new ConstantStringType(''),
TypeCombinator::intersect(
new StringType(),
new AccessoryNumericStringType(),
),
),
[],
],
[
new UnionType([
new IntersectionType(
[
new ConstantStringType('foo'),
new AccessoryLiteralStringType(),
],
),
new IntersectionType(
[
new ConstantStringType('bar'),
new AccessoryLiteralStringType(),
],
),
]),
[
"'foo'",
"'bar'",
],
],
];
}

}

0 comments on commit 1543793

Please sign in to comment.