mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Merge pull request #6874 from orklah/fix-never-combination
fix never combination
This commit is contained in:
commit
a193ec4573
@ -37,8 +37,11 @@ use Psalm\StatementsSource;
|
||||
use Psalm\Storage\FunctionLikeStorage;
|
||||
use Psalm\Storage\MethodStorage;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
use function array_diff;
|
||||
use function array_filter;
|
||||
use function array_values;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function strpos;
|
||||
@ -57,6 +60,7 @@ class ReturnTypeAnalyzer
|
||||
* @return false|null
|
||||
*
|
||||
* @psalm-suppress PossiblyUnusedReturnValue unused but seems important
|
||||
* @psalm-suppress ComplexMethod to be refactored
|
||||
*/
|
||||
public static function verifyReturnType(
|
||||
FunctionLike $function,
|
||||
@ -224,6 +228,19 @@ class ReturnTypeAnalyzer
|
||||
return null;
|
||||
}
|
||||
|
||||
$number_of_types = count($inferred_return_type_parts);
|
||||
// we filter TNever and TEmpty that have no bearing on the return type
|
||||
if ($number_of_types > 1) {
|
||||
$inferred_return_type_parts = array_filter(
|
||||
$inferred_return_type_parts,
|
||||
static function (Union $union_type) : bool {
|
||||
return !($union_type->isNever() || $union_type->isEmpty());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$inferred_return_type_parts = array_values($inferred_return_type_parts);
|
||||
|
||||
$inferred_return_type = $inferred_return_type_parts
|
||||
? \Psalm\Type::combineUnionTypeArray($inferred_return_type_parts, $codebase)
|
||||
: Type::getVoid();
|
||||
|
@ -3,9 +3,13 @@ namespace Psalm\Internal\Type;
|
||||
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic;
|
||||
use Psalm\Type\Atomic\TEmpty;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
use Psalm\Type\Atomic\TNever;
|
||||
use Psalm\Type\Atomic\TTemplateParam;
|
||||
|
||||
use function array_filter;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function count;
|
||||
@ -793,21 +797,43 @@ class TypeExpander
|
||||
$else_conditional_return_types
|
||||
);
|
||||
|
||||
foreach ($all_conditional_return_types as $i => $conditional_return_type) {
|
||||
if ($conditional_return_type instanceof Type\Atomic\TVoid
|
||||
&& count($all_conditional_return_types) > 1
|
||||
) {
|
||||
$all_conditional_return_types[$i] = new Type\Atomic\TNull();
|
||||
$all_conditional_return_types[$i]->from_docblock = true;
|
||||
$number_of_types = count($all_conditional_return_types);
|
||||
// we filter TNever and TEmpty that have no bearing on the return type
|
||||
if ($number_of_types > 1) {
|
||||
$all_conditional_return_types = array_filter(
|
||||
$all_conditional_return_types,
|
||||
static function (Atomic $atomic_type) : bool {
|
||||
return !($atomic_type instanceof TEmpty
|
||||
|| $atomic_type instanceof TNever);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// if we still have more than one type, we remove TVoid and replace it by TNull
|
||||
$number_of_types = count($all_conditional_return_types);
|
||||
if ($number_of_types > 1) {
|
||||
$all_conditional_return_types = array_filter(
|
||||
$all_conditional_return_types,
|
||||
static function (Atomic $atomic_type) : bool {
|
||||
return !$atomic_type instanceof Atomic\TVoid;
|
||||
}
|
||||
);
|
||||
|
||||
if (count($all_conditional_return_types) !== $number_of_types) {
|
||||
$null_type = new Type\Atomic\TNull();
|
||||
$null_type->from_docblock = true;
|
||||
$all_conditional_return_types[] = $null_type;
|
||||
}
|
||||
}
|
||||
|
||||
$combined = TypeCombiner::combine(
|
||||
array_values($all_conditional_return_types),
|
||||
$codebase
|
||||
);
|
||||
if ($all_conditional_return_types) {
|
||||
$combined = TypeCombiner::combine(
|
||||
array_values($all_conditional_return_types),
|
||||
$codebase
|
||||
);
|
||||
|
||||
return array_values($combined->getAtomicTypes());
|
||||
return array_values($combined->getAtomicTypes());
|
||||
}
|
||||
}
|
||||
|
||||
$return_type->conditional_type = self::expandUnion(
|
||||
|
@ -978,6 +978,30 @@ class ReturnTypeTest extends TestCase
|
||||
}
|
||||
}'
|
||||
],
|
||||
'NeverAndVoid' => [
|
||||
'<?php
|
||||
function foo(): void
|
||||
{
|
||||
foreach ([0, 1, 2] as $_i) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \Exception();
|
||||
}'
|
||||
],
|
||||
'neverAndVoidOnConditional' => [
|
||||
'<?php
|
||||
/**
|
||||
* @template T as bool
|
||||
* @param T $end
|
||||
* @return (T is true ? never : void)
|
||||
*/
|
||||
function a($end): void{
|
||||
if($end){
|
||||
die();
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user