Skip to content

Commit

Permalink
Remove unnecessary references to empty in TypeCombiner
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug authored and orklah committed Dec 20, 2021
1 parent 35a354d commit de71e27
Show file tree
Hide file tree
Showing 9 changed files with 23 additions and 28 deletions.
13 changes: 7 additions & 6 deletions docs/annotating_code/type_syntax/atomic_types.md
Expand Up @@ -52,19 +52,20 @@ 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
## Top types, bottom types

### `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`
It can be aliased to `no-return` or `never-return` in docblocks. Note: it replaced the old `empty` type that used to exist in Psalm

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<never, never>`. Psalm treats `empty` in a somewhat similar fashion to `never` when combining types together — `empty|int` becomes `int`, just as `never|string` becomes `string`.
This is the _bottom type_ in PHP's type system. It's used to describe a type that has no possible value. It can happen in multiple cases:
- the actual `never` type from PHP 8.1 (can be used in docblocks for older versions). This type can be used as a return type for functions that will never return, either because they always throw exceptions or always exit()
- an union type that have been stripped for all its possible types. (For example, if a variable is `string|int` and we perform a is_bool() check in a condition, the type of the variable in the condition will be `never` as the condition will never be entered)
- it can represent a placeholder for types yet to come — a good example is the type of the empty array `[]`, which Psalm types as `array<never, never>`, the content of the array is void so it can accept any content
- it can also happen in the same context as the line above for templates that have yet to be defined

## Other

Expand Down
4 changes: 1 addition & 3 deletions docs/running_psalm/plugins/plugins_type_system.md
Expand Up @@ -27,16 +27,14 @@ The classes are as follows:

`TNull` - denotes the `null` type

`TNever` - denotes the `no-return`/`never-return` type for functions that never return, either throwing an exception or terminating (like the builtin `exit()`).
`TNever` - denotes the `no-return`/`never-return` type for functions that never return, either throwing an exception or terminating (like the builtin `exit()`). Also used for union types that can have no possible types (impossible intersections for example). Empty arrays `[]` have the type `array<never, never>`.

`TMixed` - denotes the `mixed` type, used when you don’t know the type of an expression.

`TNonEmptyMixed `- as above, but not empty. Generated for `$x` inside the `if` statement `if ($x) {...}` when `$x` is `mixed` outside.

`TEmptyMixed` - as above, but empty. Generated for `$x` inside the `if` statement `if (!$x) {...}` when `$x` is `mixed` outside.

`TEmpty` - denotes the `empty` type, used to describe a type corresponding to no value whatsoever. Empty arrays `[]` have the type `array<never, never>`.

`TIterable` - denotes the [`iterable` type](https://www.php.net/manual/en/language.types.iterable.php) (which can also result from an `is_iterable` check).

`TResource` - denotes the `resource` type (e.g. a file handle).
Expand Down
1 change: 0 additions & 1 deletion src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php
Expand Up @@ -50,7 +50,6 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer
'bool' => 'bool',
'false' => 'false',
'object' => 'object',
'empty' => 'empty',
'never' => 'never',
'callable' => 'callable',
'array' => 'array',
Expand Down
14 changes: 5 additions & 9 deletions src/Psalm/Internal/Type/TypeCombiner.php
Expand Up @@ -9,7 +9,6 @@
use Psalm\Type\Atomic\Scalar;
use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TArrayKey;
use Psalm\Type\Atomic\TAssertionEmpty;
use Psalm\Type\Atomic\TBool;
use Psalm\Type\Atomic\TCallable;
use Psalm\Type\Atomic\TCallableArray;
Expand Down Expand Up @@ -79,8 +78,8 @@ class TypeCombiner
* - so `int + string = int|string`
* - so `array<int> + array<string> = array<int|string>`
* - and `array<int> + string = array<int>|string`
* - and `array<empty> + array<empty> = array<empty>`
* - and `array<string> + array<empty> = array<string>`
* - and `array<never> + array<never> = array<never>`
* - and `array<string> + array<never> = array<string>`
* - and `array + array<string> = array<mixed>`
*
* @param non-empty-list<Atomic> $types
Expand Down Expand Up @@ -337,20 +336,17 @@ public static function combine(
$combination->value_types += $combination->named_object_types;
}

$has_empty = (int) (isset($combination->value_types['never']) || isset($combination->value_types['empty']));
$has_never = false;
$has_never = isset($combination->value_types['never']);

foreach ($combination->value_types as $type) {
if ($type instanceof TMixed
&& $combination->mixed_from_loop_isset
&& (count($combination->value_types) > (1 + $has_empty) || count($new_types) > $has_empty)
&& (count($combination->value_types) > (1 + (int) $has_never) || count($new_types) > (int) $has_never)
) {
continue;
}

if (($type instanceof TNever || $type instanceof TAssertionEmpty)
&& (count($combination->value_types) > 1 || count($new_types))
) {
if ($type instanceof TNever && (count($combination->value_types) > 1 || count($new_types))) {
$has_never = true;
continue;
}
Expand Down
1 change: 1 addition & 0 deletions src/Psalm/Type/Atomic/TAssertionEmpty.php
@@ -1,4 +1,5 @@
<?php

namespace Psalm\Type\Atomic;

use Psalm\Type\Atomic;
Expand Down
2 changes: 1 addition & 1 deletion src/Psalm/Type/Union.php
Expand Up @@ -1206,7 +1206,7 @@ public function isGenerator(): bool

public function isEmpty(): bool
{
return isset($this->types['empty']) || isset($this->types['never']);
return $this->isNever();
}

public function substitute(Union $old_type, ?Union $new_type = null): void
Expand Down
4 changes: 2 additions & 2 deletions stubs/CoreGenericIterators.phpstub
Expand Up @@ -446,11 +446,11 @@ class DirectoryIterator extends SplFileInfo implements SeekableIterator {
*/
class EmptyIterator implements Iterator {
/**
* @return empty
* @return never
*/
public function current() {}
/**
* @return empty
* @return never
*/
public function key() {}
/**
Expand Down
4 changes: 2 additions & 2 deletions tests/ArrayFunctionCallTest.php
Expand Up @@ -1170,7 +1170,7 @@ function makeArray(): array { return [1, 3]; }
],
'arrayResetEmptyList' => [
'<?php
/** @return list<empty> */
/** @return list<never> */
function makeArray(): array { return []; }
$a = makeArray();
$b = reset($a);',
Expand Down Expand Up @@ -1246,7 +1246,7 @@ function makeArray(): array { return [1, 3]; }
],
'arrayEndEmptyList' => [
'<?php
/** @return list<empty> */
/** @return list<never> */
function makeArray(): array { return []; }
$a = makeArray();
$b = end($a);',
Expand Down
8 changes: 4 additions & 4 deletions tests/TypeCombinationTest.php
Expand Up @@ -109,10 +109,10 @@ public function providerTestValidTypeCombination(): array
'null',
],
],
'mixedOrEmpty' => [
'mixedOrNever' => [
'mixed',
[
'empty',
'never',
'mixed',
],
],
Expand Down Expand Up @@ -206,7 +206,7 @@ public function providerTestValidTypeCombination(): array
'arrayStringOrEmptyArray' => [
'array<array-key, string>',
[
'array<empty>',
'array<never>',
'array<string>',
],
],
Expand All @@ -227,7 +227,7 @@ public function providerTestValidTypeCombination(): array
'arrayMixedOrEmpty' => [
'array<array-key, mixed>',
[
'array<empty>',
'array<never>',
'array<mixed>',
],
],
Expand Down

0 comments on commit de71e27

Please sign in to comment.