From 4901208c2e9db828554baa46232983bc5fb6a027 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Wed, 5 Feb 2025 16:37:58 +0900 Subject: [PATCH 1/5] Improved support for enum-string types --- src/PhpDoc/TypeNodeResolver.php | 6 ++- .../Analyser/nsrt/more-type-strings-php8.php | 40 +++++++++++++++++++ tests/PHPStan/Analyser/nsrt/more-types.php | 2 +- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php diff --git a/src/PhpDoc/TypeNodeResolver.php b/src/PhpDoc/TypeNodeResolver.php index aa159d23a4..2c025d7bef 100644 --- a/src/PhpDoc/TypeNodeResolver.php +++ b/src/PhpDoc/TypeNodeResolver.php @@ -235,9 +235,11 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco case 'class-string': case 'interface-string': case 'trait-string': - case 'enum-string': return new ClassStringType(); + case 'enum-string': + return new GenericClassStringType(new ObjectType('UnitEnum')); + case 'callable-string': return new IntersectionType([new StringType(), new CallableType()]); @@ -696,7 +698,7 @@ static function (string $variance): TemplateTypeVariance { if (count($genericTypes) === 2) { // iterable return new IterableType($genericTypes[0], $genericTypes[1]); } - } elseif (in_array($mainTypeName, ['class-string', 'interface-string'], true)) { + } elseif (in_array($mainTypeName, ['class-string', 'interface-string', 'enum-string'], true)) { if (count($genericTypes) === 1) { $genericType = $genericTypes[0]; if ($genericType->isObject()->yes() || $genericType instanceof MixedType) { diff --git a/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php b/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php new file mode 100644 index 0000000000..9b4bc5180f --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php @@ -0,0 +1,40 @@ += 8.0 + +namespace MoreTypeStringsPhp8; + +use function PHPStan\Testing\assertType; + +class Foo +{ + + /** + * @param interface-string $interfaceString + * @param trait-string $traitString + * @param interface-string $genericInterfaceString + * @param trait-string $genericTraitString + * @param enum-string $genericEnumString + */ + public function doFoo( + string $interfaceString, + string $traitString, + string $genericInterfaceString, + string $genericTraitString, + string $genericEnumString, + ): void + { + assertType('class-string', $interfaceString); + assertType('class-string', $traitString); + assertType('class-string', $genericInterfaceString); + assertType('string', $genericTraitString); + assertType('class-string', $genericEnumString); + } + +} + +enum Bar +{ + + case A; + case B; + +} diff --git a/tests/PHPStan/Analyser/nsrt/more-types.php b/tests/PHPStan/Analyser/nsrt/more-types.php index e98bc06a76..c8ae927b2d 100644 --- a/tests/PHPStan/Analyser/nsrt/more-types.php +++ b/tests/PHPStan/Analyser/nsrt/more-types.php @@ -42,7 +42,7 @@ public function doFoo( assertType('array&callable(): mixed', $callableArray); assertType('resource', $closedResource); assertType('resource', $openResource); - assertType('class-string', $enumString); + assertType('class-string', $enumString); assertType('literal-string&non-empty-string', $nonEmptyLiteralString); assertType('float|int|int<1, max>|non-falsy-string|true', $nonEmptyScalar); assertType("0|0.0|''|'0'|false", $emptyScalar); From 5eaf06a594937302a97f9b4ebee43d8e68cb85e8 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Wed, 5 Feb 2025 18:42:29 +0900 Subject: [PATCH 2/5] fixup! Improved support for enum-string types --- src/PhpDoc/TypeNodeResolver.php | 14 ++++++++++++-- .../Analyser/nsrt/more-type-strings-php8.php | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/PhpDoc/TypeNodeResolver.php b/src/PhpDoc/TypeNodeResolver.php index 2c025d7bef..d5529c5618 100644 --- a/src/PhpDoc/TypeNodeResolver.php +++ b/src/PhpDoc/TypeNodeResolver.php @@ -107,6 +107,7 @@ use PHPStan\Type\ValueOfType; use PHPStan\Type\VoidType; use Traversable; +use UnitEnum; use function array_key_exists; use function array_map; use function array_values; @@ -238,7 +239,7 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco return new ClassStringType(); case 'enum-string': - return new GenericClassStringType(new ObjectType('UnitEnum')); + return new GenericClassStringType(new ObjectType(UnitEnum::class)); case 'callable-string': return new IntersectionType([new StringType(), new CallableType()]); @@ -698,7 +699,7 @@ static function (string $variance): TemplateTypeVariance { if (count($genericTypes) === 2) { // iterable return new IterableType($genericTypes[0], $genericTypes[1]); } - } elseif (in_array($mainTypeName, ['class-string', 'interface-string', 'enum-string'], true)) { + } elseif (in_array($mainTypeName, ['class-string', 'interface-string'], true)) { if (count($genericTypes) === 1) { $genericType = $genericTypes[0]; if ($genericType->isObject()->yes() || $genericType instanceof MixedType) { @@ -706,6 +707,15 @@ static function (string $variance): TemplateTypeVariance { } } + return new ErrorType(); + } elseif ($mainTypeName === 'enum-string') { + if (count($genericTypes) === 1) { + $genericType = $genericTypes[0]; + if ($genericType->isObject()->yes() || $genericType instanceof MixedType) { + return new GenericClassStringType(TypeCombinator::intersect($genericType, new ObjectType(UnitEnum::class))); + } + } + return new ErrorType(); } elseif ($mainTypeName === 'int') { if (count($genericTypes) === 2) { // int, int<1, 3> diff --git a/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php b/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php index 9b4bc5180f..020a43d2fa 100644 --- a/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php +++ b/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php @@ -13,6 +13,7 @@ class Foo * @param interface-string $genericInterfaceString * @param trait-string $genericTraitString * @param enum-string $genericEnumString + * @param enum-string $genericInterfaceEnumString */ public function doFoo( string $interfaceString, @@ -20,6 +21,7 @@ public function doFoo( string $genericInterfaceString, string $genericTraitString, string $genericEnumString, + string $genericInterfaceEnumString, ): void { assertType('class-string', $interfaceString); @@ -27,6 +29,7 @@ public function doFoo( assertType('class-string', $genericInterfaceString); assertType('string', $genericTraitString); assertType('class-string', $genericEnumString); + assertType('class-string', $genericInterfaceEnumString); } } @@ -38,3 +41,8 @@ enum Bar case B; } + +interface BuzInterface +{ + +} From f6f5763dffaff5b9d4394665f1aeab661ba264a0 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Wed, 5 Feb 2025 19:01:23 +0900 Subject: [PATCH 3/5] fixup! fixup! Improved support for enum-string types --- src/PhpDoc/TypeNodeResolver.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PhpDoc/TypeNodeResolver.php b/src/PhpDoc/TypeNodeResolver.php index d5529c5618..9c7249ec9c 100644 --- a/src/PhpDoc/TypeNodeResolver.php +++ b/src/PhpDoc/TypeNodeResolver.php @@ -107,7 +107,6 @@ use PHPStan\Type\ValueOfType; use PHPStan\Type\VoidType; use Traversable; -use UnitEnum; use function array_key_exists; use function array_map; use function array_values; @@ -239,7 +238,7 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco return new ClassStringType(); case 'enum-string': - return new GenericClassStringType(new ObjectType(UnitEnum::class)); + return new GenericClassStringType(new ObjectType('UnitEnum')); case 'callable-string': return new IntersectionType([new StringType(), new CallableType()]); @@ -712,7 +711,7 @@ static function (string $variance): TemplateTypeVariance { if (count($genericTypes) === 1) { $genericType = $genericTypes[0]; if ($genericType->isObject()->yes() || $genericType instanceof MixedType) { - return new GenericClassStringType(TypeCombinator::intersect($genericType, new ObjectType(UnitEnum::class))); + return new GenericClassStringType(TypeCombinator::intersect($genericType, new ObjectType('UnitEnum'))); } } From 61d568e5ae53c74f75bfc97347dc7855bf057ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mirtes?= Date: Wed, 5 Feb 2025 11:18:41 +0100 Subject: [PATCH 4/5] Update src/PhpDoc/TypeNodeResolver.php --- src/PhpDoc/TypeNodeResolver.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PhpDoc/TypeNodeResolver.php b/src/PhpDoc/TypeNodeResolver.php index 9c7249ec9c..1b9403b7c5 100644 --- a/src/PhpDoc/TypeNodeResolver.php +++ b/src/PhpDoc/TypeNodeResolver.php @@ -710,9 +710,7 @@ static function (string $variance): TemplateTypeVariance { } elseif ($mainTypeName === 'enum-string') { if (count($genericTypes) === 1) { $genericType = $genericTypes[0]; - if ($genericType->isObject()->yes() || $genericType instanceof MixedType) { - return new GenericClassStringType(TypeCombinator::intersect($genericType, new ObjectType('UnitEnum'))); - } + return new GenericClassStringType(TypeCombinator::intersect($genericType, new ObjectType('UnitEnum'))); } return new ErrorType(); From db1653f11010bdf840fb9030c012fdd310debea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mirtes?= Date: Wed, 5 Feb 2025 11:22:23 +0100 Subject: [PATCH 5/5] Update tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php --- tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php b/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php index 020a43d2fa..d81c6e9907 100644 --- a/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php +++ b/tests/PHPStan/Analyser/nsrt/more-type-strings-php8.php @@ -1,4 +1,4 @@ -= 8.0 += 8.1 namespace MoreTypeStringsPhp8;