From b51b5ac90337925b53f44f718d563e80117100d3 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Mon, 18 Jul 2022 14:10:06 -0500 Subject: [PATCH 1/3] Allow `value-of` to work with backed enums (fixes #7874). --- UPGRADING.md | 8 +- .../plugins/plugins_type_system.md | 4 +- .../Type/Comparator/AtomicTypeComparator.php | 4 +- .../Type/TemplateInferredTypeReplacer.php | 6 +- src/Psalm/Internal/Type/TypeExpander.php | 16 ++-- src/Psalm/Internal/Type/TypeParser.php | 8 +- src/Psalm/Type/Atomic/TIntMaskOf.php | 4 +- src/Psalm/Type/Atomic/TTemplateValueOf.php | 2 +- .../{TValueOfArray.php => TValueOf.php} | 55 ++++++++---- .../{ValueOfArrayTest.php => ValueOfTest.php} | 87 ++++++++++++++++++- 10 files changed, 152 insertions(+), 42 deletions(-) rename src/Psalm/Type/Atomic/{TValueOfArray.php => TValueOf.php} (53%) rename tests/{ValueOfArrayTest.php => ValueOfTest.php} (70%) diff --git a/UPGRADING.md b/UPGRADING.md index 56fa6b6d5..ad63118b2 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -64,7 +64,7 @@ - `Psalm\Type\Atomic\TTraitString` - `Psalm\Type\Atomic\TTrue` - `Psalm\Type\Atomic\TTypeAlias` - - `Psalm\Type\Atomic\TValueOfArray` + - `Psalm\Type\Atomic\TValueOf` - `Psalm\Type\Atomic\TVoid` - `Psalm\Type\Union` @@ -109,7 +109,7 @@ - `Psalm\Type\Atomic\TTemplateParam` - `Psalm\Type\Atomic\TTraitString` - `Psalm\Type\Atomic\TTypeAlias` - - `Psalm\Type\Atomic\TValueOfArray` + - `Psalm\Type\Atomic\TValueOf` - `Psalm\Type\Atomic\TVoid` - `Psalm\Type\Union` - While not a BC break per se, all classes / interfaces / traits / enums under @@ -156,7 +156,7 @@ - [BC] To remove a variable from the context, use `Context::remove()`. Calling `unset($context->vars_in_scope[$var_id])` can cause problems when using references. - [BC] `TKeyOfClassConstant` has been renamed to `TKeyOfArray`. -- [BC] `TValueOfClassConstant` has been renamed to `TValueOfArray`. +- [BC] `TValueOfClassConstant` has been renamed to `TValueOf`. - [BC] `TKeyOfTemplate` base class has been changed from `Scalar` to `Atomic`. - [BC] Class `Psalm\FileManipulation` became final - [BC] Class `Psalm\Context` became final @@ -742,7 +742,7 @@ - [BC] Class `Psalm\Type\Atomic\TLiteralInt` became final - [BC] Class `Psalm\Type\Atomic\TTrue` became final - [BC] Class `Psalm\Type\Atomic\TDependentGetClass` became final - - [BC] Class `Psalm\Type\Atomic\TValueOfArray` became final + - [BC] Class `Psalm\Type\Atomic\TValueOf` became final - [BC] Class `Psalm\Type\Atomic\TGenericObject` became final - [BC] Class `Psalm\Type\Atomic\TNonEmptyLowercaseString` became final - [BC] Class `Psalm\Type\Atomic\TEnumCase` became final diff --git a/docs/running_psalm/plugins/plugins_type_system.md b/docs/running_psalm/plugins/plugins_type_system.md index 777c4018a..ff185ee19 100644 --- a/docs/running_psalm/plugins/plugins_type_system.md +++ b/docs/running_psalm/plugins/plugins_type_system.md @@ -51,13 +51,13 @@ The classes are as follows: `TKeyOfArray` - Represents an offset of an array (e.g. `key-of`). -`TValueOfArray` - Represents a value of an array (e.g. `value-of`). +`TValueOf` - Represents a value of an array or enum (e.g. `value-of`). `TTemplateIndexedAccess` - To be documented `TTemplateKeyOf` - Represents the type used when using TKeyOfArray when the type of the array is a template -`TTemplateValueOf` - Represents the type used when using TValueOfArray when the type of the array is a template +`TTemplateValueOf` - Represents the type used when using TValueOf when the type of the array or enum is a template `TPropertiesOf` - Represents properties and their types of a class as a keyed array (e.g. `properties-of`) diff --git a/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php b/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php index f2eed358f..d009b9fd5 100644 --- a/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php +++ b/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php @@ -36,7 +36,7 @@ use Psalm\Type\Atomic\TString; use Psalm\Type\Atomic\TTemplateKeyOf; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTemplateValueOf; -use Psalm\Type\Atomic\TValueOfArray; +use Psalm\Type\Atomic\TValueOf; use function array_merge; use function array_values; @@ -375,7 +375,7 @@ class AtomicTypeComparator } if ($input_type_part instanceof TTemplateValueOf) { - $array_value_type = TValueOfArray::getArrayValueType($input_type_part->as); + $array_value_type = TValueOf::getValueType($input_type_part->as, $codebase); if ($array_value_type === null) { return false; } diff --git a/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php b/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php index 000dbf49b..4a855429f 100644 --- a/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php +++ b/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php @@ -26,7 +26,7 @@ use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTemplateParamClass; use Psalm\Type\Atomic\TTemplatePropertiesOf; use Psalm\Type\Atomic\TTemplateValueOf; -use Psalm\Type\Atomic\TValueOfArray; +use Psalm\Type\Atomic\TValueOf; use Psalm\Type\Union; use UnexpectedValueException; @@ -351,9 +351,9 @@ class TemplateInferredTypeReplacer } if ($atomic_type instanceof TTemplateValueOf - && TValueOfArray::isViableTemplateType($template_type) + && TValueOf::isViableTemplateType($template_type) ) { - return new TValueOfArray(clone $template_type); + return new TValueOf(clone $template_type); } return null; diff --git a/src/Psalm/Internal/Type/TypeExpander.php b/src/Psalm/Internal/Type/TypeExpander.php index effe35c34..c849fc1ff 100644 --- a/src/Psalm/Internal/Type/TypeExpander.php +++ b/src/Psalm/Internal/Type/TypeExpander.php @@ -34,7 +34,7 @@ use Psalm\Type\Atomic\TObjectWithProperties; use Psalm\Type\Atomic\TPropertiesOf; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTypeAlias; -use Psalm\Type\Atomic\TValueOfArray; +use Psalm\Type\Atomic\TValueOf; use Psalm\Type\Atomic\TVoid; use Psalm\Type\Union; use ReflectionProperty; @@ -364,9 +364,9 @@ class TypeExpander } if ($return_type instanceof TKeyOfArray - || $return_type instanceof TValueOfArray + || $return_type instanceof TValueOf ) { - return self::expandKeyOfValueOfArray( + return self::expandKeyOfValueOf( $codebase, $return_type, $self_class, @@ -965,11 +965,11 @@ class TypeExpander } /** - * @param TKeyOfArray|TValueOfArray $return_type + * @param TKeyOfArray|TValueOf $return_type * @param string|TNamedObject|TTemplateParam|null $static_class_type * @return non-empty-list */ - private static function expandKeyOfValueOfArray( + private static function expandKeyOfValueOf( Codebase $codebase, Atomic &$return_type, ?string $self_class, @@ -1029,8 +1029,8 @@ class TypeExpander && !TKeyOfArray::isViableTemplateType($constant_type) ) || ( - $return_type instanceof TValueOfArray - && !TValueOfArray::isViableTemplateType($constant_type) + $return_type instanceof TValueOf + && !TValueOf::isViableTemplateType($constant_type) ) ) { if ($throw_on_unresolvable_constant) { @@ -1052,7 +1052,7 @@ class TypeExpander if ($return_type instanceof TKeyOfArray) { $new_return_types = TKeyOfArray::getArrayKeyType(new Union($type_atomics)); } else { - $new_return_types = TValueOfArray::getArrayValueType(new Union($type_atomics)); + $new_return_types = TValueOf::getValueType(new Union($type_atomics), $codebase); } if ($new_return_types === null) { return [$return_type]; diff --git a/src/Psalm/Internal/Type/TypeParser.php b/src/Psalm/Internal/Type/TypeParser.php index 7b1fe60a8..00b61b9c3 100644 --- a/src/Psalm/Internal/Type/TypeParser.php +++ b/src/Psalm/Internal/Type/TypeParser.php @@ -63,7 +63,7 @@ use Psalm\Type\Atomic\TTemplateParamClass; use Psalm\Type\Atomic\TTemplatePropertiesOf; use Psalm\Type\Atomic\TTemplateValueOf; use Psalm\Type\Atomic\TTypeAlias; -use Psalm\Type\Atomic\TValueOfArray; +use Psalm\Type\Atomic\TValueOf; use Psalm\Type\TypeNode; use Psalm\Type\Union; @@ -765,13 +765,13 @@ class TypeParser ); } - if (!TValueOfArray::isViableTemplateType($generic_params[0])) { + if (!TValueOf::isViableTemplateType($generic_params[0])) { throw new TypeParseTreeException( 'Untemplated value-of param ' . $param_name . ' should be an array' ); } - return new TValueOfArray($generic_params[0]); + return new TValueOf($generic_params[0]); } if ($generic_type_value === 'int-mask') { @@ -842,7 +842,7 @@ class TypeParser $param_type = $param_union_types[0]; if (!$param_type instanceof TClassConstant - && !$param_type instanceof TValueOfArray + && !$param_type instanceof TValueOf && !$param_type instanceof TKeyOfArray ) { throw new TypeParseTreeException( diff --git a/src/Psalm/Type/Atomic/TIntMaskOf.php b/src/Psalm/Type/Atomic/TIntMaskOf.php index 056cab2bc..c7c2ca058 100644 --- a/src/Psalm/Type/Atomic/TIntMaskOf.php +++ b/src/Psalm/Type/Atomic/TIntMaskOf.php @@ -11,11 +11,11 @@ use Psalm\Type\Atomic; */ final class TIntMaskOf extends TInt { - /** @var TClassConstant|TKeyOfArray|TValueOfArray */ + /** @var TClassConstant|TKeyOfArray|TValueOf */ public $value; /** - * @param TClassConstant|TKeyOfArray|TValueOfArray $value + * @param TClassConstant|TKeyOfArray|TValueOf $value */ public function __construct(Atomic $value) { diff --git a/src/Psalm/Type/Atomic/TTemplateValueOf.php b/src/Psalm/Type/Atomic/TTemplateValueOf.php index 68f1dacbc..d00cb5974 100644 --- a/src/Psalm/Type/Atomic/TTemplateValueOf.php +++ b/src/Psalm/Type/Atomic/TTemplateValueOf.php @@ -9,7 +9,7 @@ use Psalm\Type\Atomic; use Psalm\Type\Union; /** - * Represents the type used when using TValueOfArray when the type of the array is a template + * Represents the type used when using TValueOf when the type of the array or enum is a template */ final class TTemplateValueOf extends Atomic { diff --git a/src/Psalm/Type/Atomic/TValueOfArray.php b/src/Psalm/Type/Atomic/TValueOf.php similarity index 53% rename from src/Psalm/Type/Atomic/TValueOfArray.php rename to src/Psalm/Type/Atomic/TValueOf.php index 594571157..e2f925b9f 100644 --- a/src/Psalm/Type/Atomic/TValueOfArray.php +++ b/src/Psalm/Type/Atomic/TValueOf.php @@ -2,16 +2,21 @@ namespace Psalm\Type\Atomic; +use Psalm\Codebase; +use Psalm\Internal\Codebase\ConstantTypeResolver; +use Psalm\Storage\EnumCaseStorage; use Psalm\Type\Atomic; use Psalm\Type\Union; -use function array_merge; +use function array_map; use function array_values; +use function assert; +use function count; /** - * Represents a value of an array. + * Represents a value of an array or enum. */ -final class TValueOfArray extends Atomic +final class TValueOf extends Atomic { /** @var Union */ public $type; @@ -56,6 +61,7 @@ final class TValueOfArray extends Atomic && !$type instanceof TKeyedArray && !$type instanceof TList && !$type instanceof TPropertiesOf + && !$type instanceof TNamedObject ) { return false; } @@ -63,39 +69,58 @@ final class TValueOfArray extends Atomic return true; } - public static function getArrayValueType( + public static function getValueType( Union $type, - bool $keep_template_params = false + Codebase $codebase, + bool $keep_template_params = false, ): ?Union { $value_types = []; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TArray) { - $array_value_atomics = $atomic_type->type_params[1]; + $value_atomics = $atomic_type->type_params[1]; } elseif ($atomic_type instanceof TList) { - $array_value_atomics = $atomic_type->type_param; + $value_atomics = $atomic_type->type_param; } elseif ($atomic_type instanceof TKeyedArray) { - $array_value_atomics = $atomic_type->getGenericValueType(); + $value_atomics = $atomic_type->getGenericValueType(); } elseif ($atomic_type instanceof TTemplateParam) { if ($keep_template_params) { - $array_value_atomics = new Union([$atomic_type]); + $value_atomics = new Union([$atomic_type]); } else { - $array_value_atomics = static::getArrayValueType( + $value_atomics = static::getValueType( $atomic_type->as, + $codebase, $keep_template_params ); - if ($array_value_atomics === null) { + if ($value_atomics === null) { continue; } } + } elseif ($atomic_type instanceof TNamedObject + && $codebase->classlike_storage_provider->has($atomic_type->value) + ) { + $class_storage = $codebase->classlike_storage_provider->get($atomic_type->value); + $cases = $class_storage->enum_cases; + if (!$class_storage->is_enum + || $class_storage->enum_type === null + || count($cases) === 0 + ) { + // Invalid value-of, skip + continue; + } + + $value_atomics = new Union(array_map( + function (EnumCaseStorage $case): Atomic { + assert($case->value !== null); // Backed enum must have a value + return ConstantTypeResolver::getLiteralTypeFromScalarValue($case->value); + }, + array_values($cases), + )); } else { continue; } - $value_types = array_merge( - $value_types, - array_values($array_value_atomics->getAtomicTypes()) - ); + $value_types = [...$value_types, ...array_values($value_atomics->getAtomicTypes())]; } if ($value_types === []) { diff --git a/tests/ValueOfArrayTest.php b/tests/ValueOfTest.php similarity index 70% rename from tests/ValueOfArrayTest.php rename to tests/ValueOfTest.php index 135996e75..a117c1c85 100644 --- a/tests/ValueOfArrayTest.php +++ b/tests/ValueOfTest.php @@ -7,7 +7,7 @@ namespace Psalm\Tests; use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait; use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait; -class ValueOfArrayTest extends TestCase +class ValueOfTest extends TestCase { use InvalidCodeAnalysisTestTrait; use ValidCodeAnalysisTestTrait; @@ -141,6 +141,74 @@ class ValueOfArrayTest extends TestCase } ', ], + 'valueOfStringEnum' => [ + 'code' => ' $arg */ + function foobar(string $arg): void + { + /** @psalm-check-type-exact $arg = "foo"|"bar" */; + } + + /** @var Foo */ + $foo = Foo::Foo; + foobar($foo->value); + ', + 'assertions' => [], + 'ignored_issues' => [], + 'php_version' => '8.1', + ], + 'valueOfIntEnum' => [ + 'code' => ' $arg */ + function foobar(int $arg): void + { + /** @psalm-check-type-exact $arg = 2|3 */; + } + + /** @var Foo */ + $foo = Foo::Foo; + foobar($foo->value); + ', + 'assertions' => [], + 'ignored_issues' => [], + 'php_version' => '8.1', + ], + 'valueOfEnumUnion' => [ + 'code' => ' $arg */ + function foobar(int|string $arg): void + { + /** @psalm-check-type-exact $arg = 2|3|"foo"|"bar" */; + } + ', + 'assertions' => [], + 'ignored_issues' => [], + 'php_version' => '8.1', + ], ]; } @@ -212,6 +280,23 @@ class ValueOfArrayTest extends TestCase ', 'error_message' => 'InvalidReturnStatement' ], + 'valueOfUnitEnum' => [ + 'code' => ' $arg */ + function foobar(string $arg): void {} + ', + // TODO turn this into an InvalidDocblock with a better error message. This is difficult because it + // has to happen after scanning has finished, otherwise the class might not have been scanned yet. + 'error_message' => 'MismatchingDocblockParamType', + 'ignored_issues' => [], + 'php_version' => '8.1', + ], ]; } } From 6505d8e6d5c60c8c8e7169b8b3737ef5a5ddc488 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Mon, 18 Jul 2022 14:19:34 -0500 Subject: [PATCH 2/3] Fix trailing comma for PHP 7.4. --- src/Psalm/Type/Atomic/TValueOf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Psalm/Type/Atomic/TValueOf.php b/src/Psalm/Type/Atomic/TValueOf.php index e2f925b9f..7cabc8ffa 100644 --- a/src/Psalm/Type/Atomic/TValueOf.php +++ b/src/Psalm/Type/Atomic/TValueOf.php @@ -72,7 +72,7 @@ final class TValueOf extends Atomic public static function getValueType( Union $type, Codebase $codebase, - bool $keep_template_params = false, + bool $keep_template_params = false ): ?Union { $value_types = []; From 66ebf4a55cbcad092694032c6b43fb608881f385 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Mon, 18 Jul 2022 14:44:29 -0500 Subject: [PATCH 3/3] Rename TKeyOfArray to TKeyOf. --- UPGRADING.md | 8 ++++---- docs/running_psalm/plugins/plugins_type_system.md | 4 ++-- .../Type/Comparator/AtomicTypeComparator.php | 4 ++-- .../Internal/Type/TemplateInferredTypeReplacer.php | 6 +++--- src/Psalm/Internal/Type/TypeExpander.php | 14 +++++++------- src/Psalm/Internal/Type/TypeParser.php | 8 ++++---- src/Psalm/Type/Atomic/TIntMaskOf.php | 4 ++-- .../Type/Atomic/{TKeyOfArray.php => TKeyOf.php} | 2 +- src/Psalm/Type/Atomic/TTemplateKeyOf.php | 2 +- 9 files changed, 26 insertions(+), 26 deletions(-) rename src/Psalm/Type/Atomic/{TKeyOfArray.php => TKeyOf.php} (98%) diff --git a/UPGRADING.md b/UPGRADING.md index ad63118b2..9f2ad3f0d 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -42,7 +42,7 @@ - `Psalm\Type\Atomic\TIntRange` - `Psalm\Type\Atomic\TIterable` - `Psalm\Type\Atomic\TKeyedArray` - - `Psalm\Type\Atomic\TKeyOfArray` + - `Psalm\Type\Atomic\TKeyOf` - `Psalm\Type\Atomic\TList` - `Psalm\Type\Atomic\TLiteralClassString` - `Psalm\Type\Atomic\TLowercaseString` @@ -92,7 +92,7 @@ - `Psalm\Type\Atomic\TInt` - `Psalm\Type\Atomic\TIterable` - `Psalm\Type\Atomic\TKeyedArray` - - `Psalm\Type\Atomic\TKeyOfArray` + - `Psalm\Type\Atomic\TKeyOf` - `Psalm\Type\Atomic\TList` - `Psalm\Type\Atomic\TLiteralClassString` - `Psalm\Type\Atomic\TMixed` @@ -155,7 +155,7 @@ - [BC] Atomic::getId() has now a first param $exact. Calling the method with false will return a less detailed version of the type in some cases (similarly to what `__toString` used to return) - [BC] To remove a variable from the context, use `Context::remove()`. Calling `unset($context->vars_in_scope[$var_id])` can cause problems when using references. -- [BC] `TKeyOfClassConstant` has been renamed to `TKeyOfArray`. +- [BC] `TKeyOfClassConstant` has been renamed to `TKeyOf`. - [BC] `TValueOfClassConstant` has been renamed to `TValueOf`. - [BC] `TKeyOfTemplate` base class has been changed from `Scalar` to `Atomic`. - [BC] Class `Psalm\FileManipulation` became final @@ -748,7 +748,7 @@ - [BC] Class `Psalm\Type\Atomic\TEnumCase` became final - [BC] Class `Psalm\Type\Atomic\TCallableKeyedArray` became final - [BC] Class `Psalm\Type\Atomic\TDependentGetDebugType` became final - - [BC] Class `Psalm\Type\Atomic\TKeyOfArray` became final + - [BC] Class `Psalm\Type\Atomic\TKeyOf` became final - [BC] Class `Psalm\Type\Atomic\TNonspecificLiteralInt` became final - [BC] Class `Psalm\Type\Atomic\TObjectWithProperties` became final - [BC] Class `Psalm\Type\Atomic\TTemplateValueOf` became final diff --git a/docs/running_psalm/plugins/plugins_type_system.md b/docs/running_psalm/plugins/plugins_type_system.md index ff185ee19..fcddb74e0 100644 --- a/docs/running_psalm/plugins/plugins_type_system.md +++ b/docs/running_psalm/plugins/plugins_type_system.md @@ -49,13 +49,13 @@ The classes are as follows: `TIntMaskOf` - as above, but used with a reference to constants in code `int-mask-of` will corresponds to `1|2|3|4|5|6|7` if there are three constant 1, 2 and 4 -`TKeyOfArray` - Represents an offset of an array (e.g. `key-of`). +`TKeyOf` - Represents an offset of an array (e.g. `key-of`). `TValueOf` - Represents a value of an array or enum (e.g. `value-of`). `TTemplateIndexedAccess` - To be documented -`TTemplateKeyOf` - Represents the type used when using TKeyOfArray when the type of the array is a template +`TTemplateKeyOf` - Represents the type used when using TKeyOf when the type of the array is a template `TTemplateValueOf` - Represents the type used when using TValueOf when the type of the array or enum is a template diff --git a/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php b/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php index d009b9fd5..280644203 100644 --- a/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php +++ b/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php @@ -19,7 +19,7 @@ use Psalm\Type\Atomic\TEmptyMixed; use Psalm\Type\Atomic\TEnumCase; use Psalm\Type\Atomic\TGenericObject; use Psalm\Type\Atomic\TIterable; -use Psalm\Type\Atomic\TKeyOfArray; +use Psalm\Type\Atomic\TKeyOf; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TList; use Psalm\Type\Atomic\TLiteralString; @@ -341,7 +341,7 @@ class AtomicTypeComparator } if ($input_type_part instanceof TTemplateKeyOf) { - $array_key_type = TKeyOfArray::getArrayKeyType($input_type_part->as); + $array_key_type = TKeyOf::getArrayKeyType($input_type_part->as); if ($array_key_type === null) { return false; } diff --git a/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php b/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php index 4a855429f..6d4d75315 100644 --- a/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php +++ b/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php @@ -11,7 +11,7 @@ use Psalm\Type\Atomic\TClassString; use Psalm\Type\Atomic\TConditional; use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TIterable; -use Psalm\Type\Atomic\TKeyOfArray; +use Psalm\Type\Atomic\TKeyOf; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TLiteralInt; use Psalm\Type\Atomic\TLiteralString; @@ -345,9 +345,9 @@ class TemplateInferredTypeReplacer ); if ($atomic_type instanceof TTemplateKeyOf - && TKeyOfArray::isViableTemplateType($template_type) + && TKeyOf::isViableTemplateType($template_type) ) { - return new TKeyOfArray(clone $template_type); + return new TKeyOf(clone $template_type); } if ($atomic_type instanceof TTemplateValueOf diff --git a/src/Psalm/Internal/Type/TypeExpander.php b/src/Psalm/Internal/Type/TypeExpander.php index c849fc1ff..9fb1230a0 100644 --- a/src/Psalm/Internal/Type/TypeExpander.php +++ b/src/Psalm/Internal/Type/TypeExpander.php @@ -22,7 +22,7 @@ use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TIntMask; use Psalm\Type\Atomic\TIntMaskOf; use Psalm\Type\Atomic\TIterable; -use Psalm\Type\Atomic\TKeyOfArray; +use Psalm\Type\Atomic\TKeyOf; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TList; use Psalm\Type\Atomic\TLiteralClassString; @@ -363,7 +363,7 @@ class TypeExpander return [$return_type]; } - if ($return_type instanceof TKeyOfArray + if ($return_type instanceof TKeyOf || $return_type instanceof TValueOf ) { return self::expandKeyOfValueOf( @@ -965,7 +965,7 @@ class TypeExpander } /** - * @param TKeyOfArray|TValueOf $return_type + * @param TKeyOf|TValueOf $return_type * @param string|TNamedObject|TTemplateParam|null $static_class_type * @return non-empty-list */ @@ -1025,8 +1025,8 @@ class TypeExpander if (!$constant_type || ( - $return_type instanceof TKeyOfArray - && !TKeyOfArray::isViableTemplateType($constant_type) + $return_type instanceof TKeyOf + && !TKeyOf::isViableTemplateType($constant_type) ) || ( $return_type instanceof TValueOf @@ -1049,8 +1049,8 @@ class TypeExpander return [$return_type]; } - if ($return_type instanceof TKeyOfArray) { - $new_return_types = TKeyOfArray::getArrayKeyType(new Union($type_atomics)); + if ($return_type instanceof TKeyOf) { + $new_return_types = TKeyOf::getArrayKeyType(new Union($type_atomics)); } else { $new_return_types = TValueOf::getValueType(new Union($type_atomics), $codebase); } diff --git a/src/Psalm/Internal/Type/TypeParser.php b/src/Psalm/Internal/Type/TypeParser.php index 00b61b9c3..614be8b3c 100644 --- a/src/Psalm/Internal/Type/TypeParser.php +++ b/src/Psalm/Internal/Type/TypeParser.php @@ -41,7 +41,7 @@ use Psalm\Type\Atomic\TIntMask; use Psalm\Type\Atomic\TIntMaskOf; use Psalm\Type\Atomic\TIntRange; use Psalm\Type\Atomic\TIterable; -use Psalm\Type\Atomic\TKeyOfArray; +use Psalm\Type\Atomic\TKeyOf; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TList; use Psalm\Type\Atomic\TLiteralClassString; @@ -743,13 +743,13 @@ class TypeParser ); } - if (!TKeyOfArray::isViableTemplateType($generic_params[0])) { + if (!TKeyOf::isViableTemplateType($generic_params[0])) { throw new TypeParseTreeException( 'Untemplated key-of param ' . $param_name . ' should be an array' ); } - return new TKeyOfArray($generic_params[0]); + return new TKeyOf($generic_params[0]); } if ($generic_type_value === 'value-of') { @@ -843,7 +843,7 @@ class TypeParser if (!$param_type instanceof TClassConstant && !$param_type instanceof TValueOf - && !$param_type instanceof TKeyOfArray + && !$param_type instanceof TKeyOf ) { throw new TypeParseTreeException( 'Invalid reference passed to int-mask-of' diff --git a/src/Psalm/Type/Atomic/TIntMaskOf.php b/src/Psalm/Type/Atomic/TIntMaskOf.php index c7c2ca058..3e210e409 100644 --- a/src/Psalm/Type/Atomic/TIntMaskOf.php +++ b/src/Psalm/Type/Atomic/TIntMaskOf.php @@ -11,11 +11,11 @@ use Psalm\Type\Atomic; */ final class TIntMaskOf extends TInt { - /** @var TClassConstant|TKeyOfArray|TValueOf */ + /** @var TClassConstant|TKeyOf|TValueOf */ public $value; /** - * @param TClassConstant|TKeyOfArray|TValueOf $value + * @param TClassConstant|TKeyOf|TValueOf $value */ public function __construct(Atomic $value) { diff --git a/src/Psalm/Type/Atomic/TKeyOfArray.php b/src/Psalm/Type/Atomic/TKeyOf.php similarity index 98% rename from src/Psalm/Type/Atomic/TKeyOfArray.php rename to src/Psalm/Type/Atomic/TKeyOf.php index 632a28524..027a0e04f 100644 --- a/src/Psalm/Type/Atomic/TKeyOfArray.php +++ b/src/Psalm/Type/Atomic/TKeyOf.php @@ -11,7 +11,7 @@ use function array_values; /** * Represents an offset of an array. */ -final class TKeyOfArray extends TArrayKey +final class TKeyOf extends TArrayKey { /** @var Union */ public $type; diff --git a/src/Psalm/Type/Atomic/TTemplateKeyOf.php b/src/Psalm/Type/Atomic/TTemplateKeyOf.php index 9a679df41..bb2f5f947 100644 --- a/src/Psalm/Type/Atomic/TTemplateKeyOf.php +++ b/src/Psalm/Type/Atomic/TTemplateKeyOf.php @@ -9,7 +9,7 @@ use Psalm\Type\Atomic; use Psalm\Type\Union; /** - * Represents the type used when using TKeyOfArray when the type of the array is a template + * Represents the type used when using TKeyOf when the type of the array is a template */ final class TTemplateKeyOf extends Atomic {