From b701f8cf7857399851855eaca6a49f8a6a0654e7 Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Fri, 17 Jun 2022 10:56:12 +0200 Subject: [PATCH] Improve parenthesization for union types --- src/Type/UnionType.php | 4 +++- src/Type/VerbosityLevel.php | 5 ++++ .../Rules/Generators/YieldTypeRuleTest.php | 10 ++++++++ .../Rules/Generators/data/bug-7484.php | 23 +++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Generators/data/bug-7484.php diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index 3e7f5a1935..46dd193b45 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -203,9 +203,11 @@ public function describe(VerbosityLevel $level): string { $joinTypes = static function (array $types) use ($level): string { $typeNames = []; - foreach ($types as $type) { + foreach ($types as $i => $type) { if ($type instanceof ClosureType || $type instanceof CallableType || $type instanceof TemplateUnionType) { $typeNames[] = sprintf('(%s)', $type->describe($level)); + } elseif ($type instanceof TemplateType && $i < (count($types) - 1) && ($level->isTypeOnly() || $level->isValue())) { + $typeNames[] = sprintf('(%s)', $type->describe($level)); } elseif ($type instanceof IntersectionType) { $intersectionDescription = $type->describe($level); if (strpos($intersectionDescription, '&') !== false) { diff --git a/src/Type/VerbosityLevel.php b/src/Type/VerbosityLevel.php index fe3bfc0610..304f8c1de3 100644 --- a/src/Type/VerbosityLevel.php +++ b/src/Type/VerbosityLevel.php @@ -60,6 +60,11 @@ public function isTypeOnly(): bool return $this->value === self::TYPE_ONLY; } + public function isValue(): bool + { + return $this->value === self::VALUE; + } + /** @api */ public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acceptedType = null): self { diff --git a/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php b/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php index 15a07d334c..ce02212878 100644 --- a/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php @@ -59,4 +59,14 @@ public function testRule(): void ]); } + public function testBug7484(): void + { + $this->analyse([__DIR__ . '/data/bug-7484.php'], [ + [ + 'Generator expects key type K of int|string, (K of int)|string given.', + 21, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Generators/data/bug-7484.php b/tests/PHPStan/Rules/Generators/data/bug-7484.php new file mode 100644 index 0000000000..a0d8889a9c --- /dev/null +++ b/tests/PHPStan/Rules/Generators/data/bug-7484.php @@ -0,0 +1,23 @@ + $iterable + * @return iterable + */ +function changeKeyCase( + iterable $iterable, + int $case = CASE_LOWER +): iterable { + $callable = $case === CASE_LOWER ? 'strtolower' : 'strtoupper'; + foreach ($iterable as $key => $value) { + if (is_string($key)) { + $key = $callable($key); + } + + yield $key => $value; + } +}