1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Closure basically implements callable

This commit is contained in:
Matthew Brown 2016-10-20 18:05:28 -04:00
parent 07636468a2
commit d71d439e25
5 changed files with 20 additions and 28 deletions

View File

@ -161,6 +161,10 @@ class ClassChecker extends ClassLikeChecker
{
$interface_id = strtolower($interface);
if ($interface_id === 'callable' && $absolute_class === 'Closure') {
return true;
}
if (isset(self::$class_implements[$absolute_class][$interface_id])) {
return true;
}

View File

@ -302,7 +302,8 @@ class FunctionChecker extends FunctionLikeChecker
$function_call_arg = $call_args[$function_index];
if ($function_call_arg->value instanceof PhpParser\Node\Expr\Closure) {
$closure_return_types = \Psalm\EffectsAnalyser::getReturnTypes($function_call_arg->value->stmts, true);
$closure_yield_types = [];
$closure_return_types = \Psalm\EffectsAnalyser::getReturnTypes($function_call_arg->value->stmts, $closure_yield_types, true);
if (!$closure_return_types) {
if (IssueBuffer::accepts(

View File

@ -1116,6 +1116,8 @@ class StatementsChecker
$closure_checker->check($use_context, $context->check_methods);
$stmt->inferredType = Type::getClosure();
} elseif ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) {
if ($this->checkArrayAccess($stmt, $context, $array_assignment, $assignment_key_type, $assignment_value_type, $assignment_key_value) === false) {
return false;

View File

@ -254,6 +254,14 @@ abstract class Type
return new Union([$type]);
}
/** @return Type\Union */
public static function getClosure()
{
$type = new Atomic('Closure');
return new Union([$type]);
}
/** @return Type\Union */
public static function getArray()
{

View File

@ -153,10 +153,10 @@ class Php70Test extends PHPUnit_Framework_TestCase
public function testGeneratorWithReturn()
{
$this->markTestIncomplete('Not yet supported');
$stmts = self::$_parser->parse('<?php
/**
* @return array<int,int>
* @return Generator<int,int>
* @psalm-generator-return string
*/
function foo(int $i) : Generator {
if ($i === 1) {
@ -170,31 +170,6 @@ class Php70Test extends PHPUnit_Framework_TestCase
$file_checker = new \Psalm\Checker\FileChecker('somefile.php', $stmts);
$context = new Context('somefile.php');
$file_checker->check(true, true, $context);
$this->assertEquals('array<int,int>', (string) $context->vars_in_scope['$gen']);
$this->assertEquals('int', (string) $context->vars_in_scope['$gen2']);
}
public function testClosureCall()
{
$this->markTestIncomplete('Not yet supported');
$stmts = self::$_parser->parse('<?php
class A {private $x = 1;}
// Pre PHP 7 code
$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, "A"); // intermediate closure
$a = $getX();
// PHP 7+ code
$getX = function() {return $this->x;};
$b = $getX->call(new A);
');
$file_checker = new \Psalm\Checker\FileChecker('somefile.php', $stmts);
$context = new Context('somefile.php');
$file_checker->check(true, true, $context);
$this->assertEquals('mixed', (string) $context->vars_in_scope['$a']);
$this->assertEquals('mixed', (string) $context->vars_in_scope['$b']);
}
public function testGeneratorDelegation()
@ -202,6 +177,7 @@ class Php70Test extends PHPUnit_Framework_TestCase
$stmts = self::$_parser->parse('<?php
/**
* @return Generator<int,int>
* @psalm-generator-return int
*/
function count_to_ten() : Generator {
yield 1;
@ -229,6 +205,7 @@ class Php70Test extends PHPUnit_Framework_TestCase
/**
* @return Generator<int,int>
* @psalm-generator-return int
*/
function nine_ten() : Generator {
yield 9;