From 9c919122812c06678c08c25b50be26c6df768265 Mon Sep 17 00:00:00 2001 From: Matthew Rardon Date: Mon, 28 Mar 2022 11:38:18 -0400 Subject: [PATCH 1/2] Fix ftp_fget/_fput/_nb_fget/_nb_fput arg types --- dictionaries/CallMap.php | 8 ++++---- dictionaries/CallMap_81_delta.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dictionaries/CallMap.php b/dictionaries/CallMap.php index 593253d47..457af5a87 100644 --- a/dictionaries/CallMap.php +++ b/dictionaries/CallMap.php @@ -3343,8 +3343,8 @@ return [ 'ftp_connect' => ['FTP\Connection|false', 'hostname'=>'string', 'port='=>'int', 'timeout='=>'int'], 'ftp_delete' => ['bool', 'ftp'=>'FTP\Connection', 'filename'=>'string'], 'ftp_exec' => ['bool', 'ftp'=>'FTP\Connection', 'command'=>'string'], -'ftp_fget' => ['bool', 'ftp'=>'FTP\Connection', 'stream'=>'FTP\Connection', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], -'ftp_fput' => ['bool', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'stream'=>'FTP\Connection', 'mode='=>'int', 'offset='=>'int'], +'ftp_fget' => ['bool', 'ftp'=>'FTP\Connection', 'stream'=>'resource', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], +'ftp_fput' => ['bool', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'stream'=>'resource', 'mode='=>'int', 'offset='=>'int'], 'ftp_get' => ['bool', 'ftp'=>'FTP\Connection', 'local_filename'=>'string', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_get_option' => ['mixed|false', 'ftp'=>'FTP\Connection', 'option'=>'int'], 'ftp_login' => ['bool', 'ftp'=>'FTP\Connection', 'username'=>'string', 'password'=>'string'], @@ -3352,8 +3352,8 @@ return [ 'ftp_mkdir' => ['string|false', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_mlsd' => ['array|false', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_nb_continue' => ['int', 'ftp'=>'FTP\Connection'], -'ftp_nb_fget' => ['int', 'ftp'=>'FTP\Connection', 'stream'=>'FTP\Connection', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], -'ftp_nb_fput' => ['int', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'stream'=>'FTP\Connection', 'mode='=>'int', 'offset='=>'int'], +'ftp_nb_fget' => ['int', 'ftp'=>'FTP\Connection', 'stream'=>'resource', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], +'ftp_nb_fput' => ['int', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'stream'=>'resource', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_get' => ['int', 'ftp'=>'FTP\Connection', 'local_filename'=>'string', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_put' => ['int', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nlist' => ['array|false', 'ftp'=>'FTP\Connection', 'directory'=>'string'], diff --git a/dictionaries/CallMap_81_delta.php b/dictionaries/CallMap_81_delta.php index 81bc19a89..51b521e9a 100644 --- a/dictionaries/CallMap_81_delta.php +++ b/dictionaries/CallMap_81_delta.php @@ -135,11 +135,11 @@ return [ ], 'ftp_fget' => [ 'old' => ['bool', 'ftp' => 'resource', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], - 'new' => ['bool', 'ftp' => 'FTP\Connection', 'stream' => 'FTP\Connection', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], + 'new' => ['bool', 'ftp' => 'FTP\Connection', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_nb_fget' => [ 'old' => ['int', 'ftp' => 'resource', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], - 'new' => ['int', 'ftp' => 'FTP\Connection', 'stream' => 'FTP\Connection', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], + 'new' => ['int', 'ftp' => 'FTP\Connection', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_pasv' => [ 'old' => ['bool', 'ftp' => 'resource', 'enable' => 'bool'], @@ -159,11 +159,11 @@ return [ ], 'ftp_fput' => [ 'old' => ['bool', 'ftp' => 'resource', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], - 'new' => ['bool', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'stream' => 'FTP\Connection', 'mode=' => 'int', 'offset=' => 'int'], + 'new' => ['bool', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_nb_fput' => [ 'old' => ['int', 'ftp' => 'resource', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], - 'new' => ['int', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'stream' => 'FTP\Connection', 'mode=' => 'int', 'offset=' => 'int'], + 'new' => ['int', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_put' => [ 'old' => ['bool', 'ftp' => 'resource', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], From 0bdf9425e3f63a0259e6f28de6cc6396791f6fa7 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Wed, 30 Mar 2022 16:01:46 -0500 Subject: [PATCH 2/2] Fix namespaced min/max int range keyword issue introduced in #7775. --- src/Psalm/Internal/Type/TypeParser.php | 50 +++++++++++--------------- tests/IntRangeTest.php | 11 ++++++ 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/Psalm/Internal/Type/TypeParser.php b/src/Psalm/Internal/Type/TypeParser.php index 4560aa645..fbcad54d4 100644 --- a/src/Psalm/Internal/Type/TypeParser.php +++ b/src/Psalm/Internal/Type/TypeParser.php @@ -74,6 +74,7 @@ use function array_shift; use function array_unique; use function array_unshift; use function array_values; +use function assert; use function constant; use function count; use function defined; @@ -822,38 +823,27 @@ class TypeParser if (count($generic_params) !== 2) { throw new TypeParseTreeException('int range must have 2 params'); } + assert(count($parse_tree->children) === 2); - $param0_union_types = array_values($generic_params[0]->getAtomicTypes()); - $param1_union_types = array_values($generic_params[1]->getAtomicTypes()); + $get_int_range_bound = function (ParseTree $parse_tree, Union $generic_param, string $bound_name): ?int { + if (!$parse_tree instanceof Value + || count($generic_param->getAtomicTypes()) > 1 + || (!$generic_param->getSingleAtomic() instanceof TLiteralInt + && $parse_tree->value !== $bound_name + && $parse_tree->text !== $bound_name + ) + ) { + throw new TypeParseTreeException( + "Invalid type \"{$generic_param->getId()}\" as int $bound_name boundary" + ); + } - if (count($param0_union_types) > 1 || count($param1_union_types) > 1) { - throw new TypeParseTreeException('Union types are not allowed in int range type'); - } + $generic_param_atomic = $generic_param->getSingleAtomic(); + return $generic_param_atomic instanceof TLiteralInt ? $generic_param_atomic->value : null; + }; - if (!($param0_union_types[0] instanceof TNamedObject) && !($param0_union_types[0] instanceof TLiteralInt) || - !($param1_union_types[0] instanceof TNamedObject) && !($param1_union_types[0] instanceof TLiteralInt)) { - throw new TypeParseTreeException('Unsupported parameter'); - } - - if ($param0_union_types[0] instanceof TNamedObject - && $param0_union_types[0]->value !== TIntRange::BOUND_MIN) { - throw new TypeParseTreeException('Incorrect named object as a min boundary'); - } - - if ($param1_union_types[0] instanceof TNamedObject - && $param1_union_types[0]->value !== TIntRange::BOUND_MAX) { - throw new TypeParseTreeException('Incorrect named object as a max boundary'); - } - - $min_bound = null; - $max_bound = null; - - if ($param0_union_types[0] instanceof TLiteralInt) { - $min_bound = $param0_union_types[0]->value; - } - if ($param1_union_types[0] instanceof TLiteralInt) { - $max_bound = $param1_union_types[0]->value; - } + $min_bound = $get_int_range_bound($parse_tree->children[0], $generic_params[0], TIntRange::BOUND_MIN); + $max_bound = $get_int_range_bound($parse_tree->children[1], $generic_params[1], TIntRange::BOUND_MAX); if ($min_bound === null && $max_bound === null) { return new TInt(); @@ -865,7 +855,7 @@ class TypeParser if (is_int($min_bound) && is_int($max_bound) && $min_bound > $max_bound) { throw new TypeParseTreeException( - "Min bound can't be greater than max bound, int<" . $min_bound . "," . $max_bound . "> given" + "Min bound can't be greater than max bound, int<$min_bound, $max_bound> given" ); } diff --git a/tests/IntRangeTest.php b/tests/IntRangeTest.php index d8d26c751..d182607aa 100644 --- a/tests/IntRangeTest.php +++ b/tests/IntRangeTest.php @@ -697,6 +697,17 @@ class IntRangeTest extends TestCase '$_arr===' => 'non-empty-array, int<0, max>>', ], ], + 'minMaxInNamespace' => [ + ' $_a + * @param int $_b + */ + function bar(int $_a, int $_b): void {} + } + ', + ] ]; }