mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fix #5652 - use accurate type combination rules when replacing templated union
This commit is contained in:
parent
3d908eda7e
commit
ecd5e3b7ae
@ -51,12 +51,22 @@ Atomic types are the basic building block of all type information used in Psalm.
|
||||
- `value-of<Foo\Bar::ARRAY_CONST>`
|
||||
- `T[K]`
|
||||
|
||||
## Top types, bottom types and empty
|
||||
|
||||
### `mixed`
|
||||
|
||||
This is the _top type_ in PHP's type system, and represents a lack of type information. Psalm warns about `mixed` types when the `totallyTyped` flag is turned on, or when you're on level 1.
|
||||
|
||||
### `never`
|
||||
|
||||
This is the _bottom type_ in PHP's type system, and usually represents a return type for a function that can never actually return, such as `die()`, `exit()`, or a function that always throws an exception. It may also be written in docblocks as `no-return` or `never-return`.
|
||||
|
||||
### `empty`
|
||||
|
||||
A type that's equivalent to a "coming soon" sign. Psalm uses this type when it’s awaiting more information — a good example is the type of the empty array `[]`, which Psalm types as `array<empty, empty>`. Psalm treats `empty` in a somewhat similar fashion to `never` when combining types together — `empty|int` becomes `int`, just as `never|string` becomes `string`.
|
||||
|
||||
## Other
|
||||
|
||||
- `iterable` - represents the [iterable pseudo-type](https://php.net/manual/en/language.types.iterable.php). Like arrays, iterables can have type parameters e.g. `iterable<string, Foo>`.
|
||||
- `void` - can be used in a return type when a function does not return a value.
|
||||
- `empty` - a type that represents a lack of type - not just a lack of type information (that's where [mixed](#mixed) is useful) but where there can be no type. A good example is the type of the empty array `[]`. Psalm types this as `array<empty, empty>`.
|
||||
- `mixed` represents a lack of type information. Psalm warns about mixed when the `totallyTyped` flag is turned on.
|
||||
- `resource` represents a [PHP resource](https://www.php.net/manual/en/language.types.resource.php).
|
||||
- `no-return` is the 'return type' for a function that can never actually return, such as `die()`, `exit()`, or a function that
|
||||
always throws an exception. It may also be written as `never-return` or `never-returns`, and is also known as the _bottom type_.
|
||||
|
@ -91,7 +91,15 @@ class TemplateStandinTypeReplacer
|
||||
throw new \UnexpectedValueException('Cannot remove all keys');
|
||||
}
|
||||
|
||||
$new_union_type = new Union($atomic_types);
|
||||
if (count($atomic_types) > 1) {
|
||||
$new_union_type = \Psalm\Internal\Type\TypeCombiner::combine(
|
||||
$atomic_types,
|
||||
$codebase
|
||||
);
|
||||
} else {
|
||||
$new_union_type = new Union($atomic_types);
|
||||
}
|
||||
|
||||
$new_union_type->ignore_nullable_issues = $union_type->ignore_nullable_issues;
|
||||
$new_union_type->ignore_falsable_issues = $union_type->ignore_falsable_issues;
|
||||
$new_union_type->possibly_undefined = $union_type->possibly_undefined;
|
||||
|
@ -31,6 +31,7 @@ use Psalm\Type\Atomic\TLiteralString;
|
||||
use Psalm\Type\Atomic\TLowercaseString;
|
||||
use Psalm\Type\Atomic\TMixed;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
use Psalm\Type\Atomic\TNever;
|
||||
use Psalm\Type\Atomic\TNonEmptyArray;
|
||||
use Psalm\Type\Atomic\TNonEmptyList;
|
||||
use Psalm\Type\Atomic\TNonEmptyLowercaseString;
|
||||
@ -340,7 +341,7 @@ class TypeCombiner
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type instanceof TEmpty
|
||||
if (($type instanceof TEmpty || $type instanceof TNever)
|
||||
&& (count($combination->value_types) > 1 || count($new_types))
|
||||
) {
|
||||
continue;
|
||||
|
@ -134,9 +134,18 @@ abstract class Atomic implements TypeNode
|
||||
|
||||
break;
|
||||
|
||||
case 'never':
|
||||
if ($php_version === null
|
||||
|| ($php_version[0] > 8)
|
||||
|| ($php_version[0] === 8 && $php_version[1] >= 1)
|
||||
) {
|
||||
return new TNever();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'never-return':
|
||||
case 'never-returns':
|
||||
case 'never':
|
||||
case 'no-return':
|
||||
return new TNever();
|
||||
|
||||
|
@ -9,12 +9,12 @@ class TNever extends \Psalm\Type\Atomic
|
||||
{
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'never-return';
|
||||
return 'never';
|
||||
}
|
||||
|
||||
public function getKey(bool $include_extra = true): string
|
||||
{
|
||||
return 'never-return';
|
||||
return 'never';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -960,7 +960,7 @@ class Union implements TypeNode
|
||||
|
||||
public function isNever(): bool
|
||||
{
|
||||
return isset($this->types['never-return']);
|
||||
return isset($this->types['never']);
|
||||
}
|
||||
|
||||
public function isGenerator(): bool
|
||||
|
Loading…
Reference in New Issue
Block a user