From 56918001a833f176eac72aa079a512b9f5d70d94 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Sat, 21 Nov 2020 22:50:56 -0500 Subject: [PATCH] Fix #4643 - use PHP8 union types when possible --- src/Psalm/Type/Union.php | 52 +++++++++++-------- .../MissingReturnTypeTest.php | 28 ++++++++++ 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/Psalm/Type/Union.php b/src/Psalm/Type/Union.php index a108b07e9..789f24043 100644 --- a/src/Psalm/Type/Union.php +++ b/src/Psalm/Type/Union.php @@ -437,10 +437,11 @@ class Union implements TypeNode int $php_major_version, int $php_minor_version ): ?string { - $nullable = false; - - if (!$this->isSingleAndMaybeNullable() - || $php_major_version < 7 + if (!$this->isSingleAndMaybeNullable()) { + if ($php_major_version < 8) { + return null; + } + } elseif ($php_major_version < 7 || (isset($this->types['null']) && $php_major_version === 7 && $php_minor_version < 1) ) { return null; @@ -448,36 +449,38 @@ class Union implements TypeNode $types = $this->types; - if (isset($types['null'])) { - if (count($types) === 1) { - return null; - } + $nullable = false; + if (isset($types['null']) && count($types) === 2) { unset($types['null']); $nullable = true; } - $atomic_type = array_values($types)[0]; + $php_types = []; - $atomic_type_string = $atomic_type->toPhpString( - $namespace, - $aliased_classes, - $this_class, - $php_major_version, - $php_minor_version - ); + foreach ($types as $atomic_type) { + $php_type = $atomic_type->toPhpString( + $namespace, + $aliased_classes, + $this_class, + $php_major_version, + $php_minor_version + ); - if ($atomic_type_string) { - return ($nullable ? '?' : '') . $atomic_type_string; + if (!$php_type) { + return null; + } + + $php_types[] = $php_type; } - return null; + return ($nullable ? '?' : '') . implode('|', array_unique($php_types)); } public function canBeFullyExpressedInPhp(int $php_major_version, int $php_minor_version): bool { - if (!$this->isSingleAndMaybeNullable()) { + if (!$this->isSingleAndMaybeNullable() && $php_major_version < 8) { return false; } @@ -491,9 +494,12 @@ class Union implements TypeNode } } - $atomic_type = array_values($types)[0]; - - return $atomic_type->canBeFullyExpressedInPhp($php_major_version, $php_minor_version); + return !array_filter( + $types, + function ($atomic_type) use ($php_major_version, $php_minor_version) { + return !$atomic_type->canBeFullyExpressedInPhp($php_major_version, $php_minor_version); + } + ); } public function removeType(string $type_string): bool diff --git a/tests/FileManipulation/MissingReturnTypeTest.php b/tests/FileManipulation/MissingReturnTypeTest.php index 97c5b3481..899ae60a2 100644 --- a/tests/FileManipulation/MissingReturnTypeTest.php +++ b/tests/FileManipulation/MissingReturnTypeTest.php @@ -984,6 +984,34 @@ class MissingReturnTypeTest extends FileManipulationTest false, true, ], + 'returnIntOrString' => [ + ' [ + '