Skip to content

Commit

Permalink
implement assertions for enum-string and fix some callmap and stubs
Browse files Browse the repository at this point in the history
  • Loading branch information
orklah committed Jan 16, 2022
1 parent f8fdedd commit 6f10e18
Show file tree
Hide file tree
Showing 12 changed files with 30 additions and 6 deletions.
4 changes: 2 additions & 2 deletions dictionaries/CallMap.php
Expand Up @@ -2519,7 +2519,7 @@
'enchant_dict_store_replacement' => ['void', 'dictionary'=>'resource', 'misspelled'=>'string', 'correct'=>'string'],
'enchant_dict_suggest' => ['array', 'dictionary'=>'resource', 'word'=>'string'],
'end' => ['mixed|false', '&r_array'=>'array|object'],
'enum_exists' => ['bool', 'class' => 'class-string', 'autoload=' => 'bool'],
'enum_exists' => ['bool', 'class' => 'string', 'autoload=' => 'bool'],
'Error::__clone' => ['void'],
'Error::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable|?Error'],
'Error::__toString' => ['string'],
Expand Down Expand Up @@ -7504,7 +7504,7 @@
'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'source'=>'string'],
'MessageFormatter::setPattern' => ['bool', 'pattern'=>'string'],
'metaphone' => ['string|false', 'string'=>'string', 'max_phonemes='=>'int'],
'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string', 'method'=>'string'],
'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string|enum-string', 'method'=>'string'],
'mhash' => ['string', 'algo'=>'int', 'data'=>'string', 'key='=>'string'],
'mhash_count' => ['int'],
'mhash_get_block_size' => ['int|false', 'algo'=>'int'],
Expand Down
2 changes: 1 addition & 1 deletion dictionaries/CallMap_81_delta.php
Expand Up @@ -17,7 +17,7 @@
return [
'added' => [
'array_is_list' => ['bool', 'array' => 'array'],
'enum_exists' => ['bool', 'class' => 'class-string', 'autoload=' => 'bool'],
'enum_exists' => ['bool', 'class' => 'string', 'autoload=' => 'bool'],
'fsync' => ['bool', 'stream' => 'resource'],
'fdatasync' => ['bool', 'stream' => 'resource'],
'imageavif' => ['bool', 'image'=>'GdImage', 'file='=>'resource|string|null', 'quality='=>'int', 'speed='=>'int'],
Expand Down
2 changes: 1 addition & 1 deletion dictionaries/CallMap_historical.php
Expand Up @@ -12998,7 +12998,7 @@
'memory_get_peak_usage' => ['int', 'real_usage='=>'bool'],
'memory_get_usage' => ['int', 'real_usage='=>'bool'],
'metaphone' => ['string|false', 'string'=>'string', 'max_phonemes='=>'int'],
'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string', 'method'=>'string'],
'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string|enum-string', 'method'=>'string'],
'mhash' => ['string', 'algo'=>'int', 'data'=>'string', 'key='=>'string'],
'mhash_count' => ['int'],
'mhash_get_block_size' => ['int|false', 'algo'=>'int'],
Expand Down
1 change: 1 addition & 0 deletions docs/annotating_code/type_syntax/atomic_types.md
Expand Up @@ -10,6 +10,7 @@ Atomic types are the basic building block of all type information used in Psalm.
- [string](scalar_types.md)
- [class-string and class-string<Foo>](scalar_types.md#class-string-interface-string)
- [trait-string](scalar_types.md#trait-string)
- [enum-string](scalar_types.md#enum-string)
- [callable-string](scalar_types.md#callable-string)
- [numeric-string](scalar_types.md#numeric-string)
- [literal-string](scalar_types.md#literal-string)
Expand Down
4 changes: 4 additions & 0 deletions docs/annotating_code/type_syntax/scalar_types.md
Expand Up @@ -42,6 +42,10 @@ You can also parameterize `class-string` with an object name e.g. [`class-string

Psalm also supports a `trait-string` annotation denote a trait that exists.

### enum-string

Psalm also supports a `enum-string` annotation denote an enum that exists.

### callable-string

`callable-string` denotes a string value that has passed an `is_callable` check.
Expand Down
Expand Up @@ -787,6 +787,14 @@ public static function processFunctionCall(
$if_types[$first_var_name] = [['=trait-string']];
}
}
} elseif ($class_exists_check_type = self::hasEnumExistsCheck($expr)) {
if ($first_var_name) {
if ($class_exists_check_type === 2) {
$if_types[$first_var_name] = [['enum-string']];
} else {
$if_types[$first_var_name] = [['=enum-string']];
}
}
} elseif (self::hasInterfaceExistsCheck($expr)) {
if ($first_var_name) {
$if_types[$first_var_name] = [['interface-string']];
Expand Down
5 changes: 5 additions & 0 deletions src/Psalm/Internal/Type/AssertionReconciler.php
Expand Up @@ -1026,6 +1026,7 @@ private static function handleLiteralEquality(
|| $scalar_type === 'interface-string'
|| $scalar_type === 'callable-string'
|| $scalar_type === 'trait-string'
|| $scalar_type === 'enum-string'
) {
return self::handleLiteralEqualityWithString(
$statements_analyzer,
Expand Down Expand Up @@ -1313,6 +1314,7 @@ private static function handleLiteralEqualityWithString(
if ($scalar_type === 'class-string'
|| $scalar_type === 'interface-string'
|| $scalar_type === 'trait-string'
|| $scalar_type === 'enum-string'
) {
return $literal_asserted_type_classstring;
}
Expand All @@ -1324,6 +1326,7 @@ private static function handleLiteralEqualityWithString(
if ($scalar_type === 'class-string'
|| $scalar_type === 'interface-string'
|| $scalar_type === 'trait-string'
|| $scalar_type === 'enum-string'
) {
return $literal_asserted_type_classstring;
}
Expand All @@ -1347,6 +1350,7 @@ private static function handleLiteralEqualityWithString(
if ($scalar_type === 'class-string'
|| $scalar_type === 'interface-string'
|| $scalar_type === 'trait-string'
|| $scalar_type === 'enum-string'
) {
return $literal_asserted_type_classstring;
}
Expand Down Expand Up @@ -1615,6 +1619,7 @@ private static function getCompatibleStringType(
if ($scalar_type === 'class-string'
|| $scalar_type === 'interface-string'
|| $scalar_type === 'trait-string'
|| $scalar_type === 'enum-string'
) {
$asserted_type = new Union([new TLiteralClassString($value)]);
$asserted_type->from_docblock = $existing_var_type->from_docblock;
Expand Down
1 change: 1 addition & 0 deletions src/Psalm/Internal/Type/NegatedAssertionReconciler.php
Expand Up @@ -313,6 +313,7 @@ private static function handleLiteralNegatedEquality(
|| $scalar_type === 'interface-string'
|| $scalar_type === 'trait-string'
|| $scalar_type === 'callable-string'
|| $scalar_type === 'enum-string'
) {
if ($existing_var_type->hasString()) {
if ($existing_string_types = $existing_var_type->getLiteralStrings()) {
Expand Down
5 changes: 4 additions & 1 deletion src/Psalm/Internal/Type/TypeParser.php
Expand Up @@ -617,7 +617,10 @@ private static function getTypeFromGenericTree(
return new TNonEmptyList($generic_params[0]);
}

if ($generic_type_value === 'class-string' || $generic_type_value === 'interface-string') {
if ($generic_type_value === 'class-string'
|| $generic_type_value === 'interface-string'
|| $generic_type_value === 'enum-string'
) {
$class_name = (string)$generic_params[0];

if (isset($template_type_map[$class_name])) {
Expand Down
1 change: 1 addition & 0 deletions src/Psalm/Internal/Type/TypeTokenizer.php
Expand Up @@ -44,6 +44,7 @@ class TypeTokenizer
'numeric-string' => true,
'class-string' => true,
'interface-string' => true,
'enum-string' => true,
'trait-string' => true,
'callable-string' => true,
'callable-array' => true,
Expand Down
1 change: 1 addition & 0 deletions src/Psalm/Type/Atomic.php
Expand Up @@ -271,6 +271,7 @@ public static function create(

case 'class-string':
case 'interface-string':
case 'enum-string':
return new TClassString();

case 'trait-string':
Expand Down
2 changes: 1 addition & 1 deletion stubs/Reflection.phpstub
Expand Up @@ -13,7 +13,7 @@ class ReflectionClass implements Reflector {
public $name;

/**
* @param T|class-string<T>|interface-string<T>|trait-string $argument
* @param T|class-string<T>|interface-string<T>|trait-string|enum-string<T> $argument
*/
public function __construct($argument) {}

Expand Down

0 comments on commit 6f10e18

Please sign in to comment.