From 7e07d619ae084bb12aa2f45ba123faea4f2e9b35 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 30 Jun 2026 16:36:50 +0200 Subject: [PATCH] [TypeDeclaration] Map accessory string intersection to string in union return type ReturnUnionTypeRector inferred 0|(numeric-string&non-falsy-string) returns but IntersectionTypeMapper only handled object intersections, returning null for the string-accessory member and aborting the whole union. Map a pure-string intersection to string so int|string is added. --- .../Fixture/int_or_numeric_string.php.inc | 57 +++++++++++++++++++ .../TypeMapper/IntersectionTypeMapper.php | 6 ++ 2 files changed, 63 insertions(+) create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/int_or_numeric_string.php.inc diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/int_or_numeric_string.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/int_or_numeric_string.php.inc new file mode 100644 index 00000000000..86816ba6d94 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/int_or_numeric_string.php.inc @@ -0,0 +1,57 @@ +getAssetSize($assets); + + if ($size) { + $size = (string) $size; + } + + return $size; + } +} + +?> +----- +getAssetSize($assets); + + if ($size) { + $size = (string) $size; + } + + return $size; + } +} + +?> diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php index e64fb9cb1aa..b6143295d8e 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php @@ -5,6 +5,7 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; use PhpParser\Node; +use PhpParser\Node\Identifier; use PhpParser\Node\Name\FullyQualified; use PHPStan\PhpDocParser\Ast\Node as AstNode; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode; @@ -91,6 +92,11 @@ function (AstNode $astNode): int|IdentifierTypeNode { */ public function mapToPhpParserNode(Type $type, string $typeKind): ?Node { + // accessory string types, e.g. "numeric-string&non-falsy-string", are just "string" + if ($type->isString()->yes()) { + return new Identifier('string'); + } + if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::INTERSECTION_TYPES)) { return null; }