diff --git a/src/Psalm/CallMap.php b/src/Psalm/CallMap.php index da548f44e..e074a2595 100644 --- a/src/Psalm/CallMap.php +++ b/src/Psalm/CallMap.php @@ -5456,7 +5456,7 @@ return [ 'is_uploaded_file' => ['bool', 'path'=>'string'], 'is_writable' => ['bool', 'filename'=>'string'], 'is_writeable' => ['bool', 'filename'=>'string'], -'isset' => ['bool', 'var'=>'mixed', 'rest='=>'...mixed='], +'isset' => ['bool', 'var'=>'mixed', '...rest='=>'mixed'], 'Iterator::current' => ['mixed'], 'Iterator::key' => ['int|string'], 'Iterator::next' => ['void'], @@ -6375,7 +6375,7 @@ return [ 'MongoCollection::getWriteConcern' => ['array'], 'MongoCollection::group' => ['array', 'keys'=>'mixed', 'initial'=>'array', 'reduce'=>'mongocode', 'options='=>'array'], 'MongoCollection::insert' => ['bool|array', 'a'=>'array', 'options='=>'array'], -'MongoCollection::parallelCollectionScan' => ['array[MongoCommandCursor]', 'num_cursors'=>'int'], +'MongoCollection::parallelCollectionScan' => ['MongoCommandCursor[]', 'num_cursors'=>'int'], 'MongoCollection::remove' => ['bool|array', 'criteria='=>'array', 'options='=>'array'], 'MongoCollection::save' => ['mixed', 'a'=>'array', 'options='=>'array'], 'MongoCollection::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], @@ -8074,7 +8074,7 @@ return [ 'pcntl_get_last_error' => ['int'], 'pcntl_getpriority' => ['int', 'pid='=>'int', 'process_identifier='=>'int'], 'pcntl_setpriority' => ['bool', 'priority'=>'int', 'pid='=>'int', 'process_identifier='=>'int'], -'pcntl_signal' => ['bool', 'signo'=>'int', 'handle'=>'(callable(mixed...):void)|int', 'restart_syscalls='=>'bool'], +'pcntl_signal' => ['bool', 'signo'=>'int', 'handle'=>'callable(mixed...):void|int', 'restart_syscalls='=>'bool'], 'pcntl_signal_dispatch' => ['bool'], 'pcntl_signal_get_handler' => ['int|string', 'signo'=>'int'], 'pcntl_sigprocmask' => ['bool', 'how'=>'int', 'set'=>'array', '&w_oldset='=>'array'], diff --git a/src/Psalm/Type/ParseTree.php b/src/Psalm/Type/ParseTree.php index c5a5c78b0..66bd33c78 100644 --- a/src/Psalm/Type/ParseTree.php +++ b/src/Psalm/Type/ParseTree.php @@ -252,6 +252,11 @@ class ParseTree case '|': $current_parent = $current_leaf->parent; + if ($current_parent instanceof ParseTree\CallableWithReturnTypeTree) { + $current_leaf = $current_parent; + $current_parent = $current_parent->parent; + } + if ($current_leaf instanceof ParseTree\UnionTree) { throw new TypeParseTreeException('Unexpected token ' . $type_token); } diff --git a/tests/TypeParseTest.php b/tests/TypeParseTest.php index 22dc92c9a..369d5d658 100644 --- a/tests/TypeParseTest.php +++ b/tests/TypeParseTest.php @@ -356,6 +356,14 @@ class TypeParseTest extends TestCase ); } + public function testCallableOrInt() + { + $this->assertSame( + 'callable(string):void|int', + (string)Type::parseString('callable(string):void|int') + ); + } + /** * @expectedException \Psalm\Exception\TypeParseTreeException * @@ -457,4 +465,52 @@ class TypeParseTest extends TestCase (string)Type::parseString('callable(int, string)') ); } + + /** + * @dataProvider providerTestValidCallMapType + * + * @param string $expected + * @param array $arr + * + * @return void + */ + public function testValidCallMapType( + $return_type, + $param_type_1 = '', + $param_type_2 = '', + $param_type_3 = '', + $param_type_4 = '' + ) { + if ($return_type && $return_type !== 'void') { + \Psalm\Type::parseString($return_type); + } + + if ($param_type_1 && $param_type_1 !== 'mixed') { + if (strpos($param_type_1, 'oci-') !== false) { + return; + } + + \Psalm\Type::parseString($param_type_1); + } + + if ($param_type_2 && $param_type_2 !== 'mixed') { + \Psalm\Type::parseString($param_type_2); + } + + if ($param_type_3 && $param_type_3 !== 'mixed') { + \Psalm\Type::parseString($param_type_3); + } + + if ($param_type_4 && $param_type_4 !== 'mixed') { + \Psalm\Type::parseString($param_type_4); + } + } + + /** + * @return void + */ + public function providerTestValidCallMapType() + { + return \Psalm\Codebase\CallMap::getCallMap(); + } }