1
0
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:
Matt Brown 2021-04-22 00:33:49 -04:00
parent 3d908eda7e
commit ecd5e3b7ae
6 changed files with 38 additions and 10 deletions

View File

@ -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 its 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_.

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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';
}
/**

View File

@ -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