mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Closure basically implements callable
This commit is contained in:
parent
07636468a2
commit
d71d439e25
@ -161,6 +161,10 @@ class ClassChecker extends ClassLikeChecker
|
|||||||
{
|
{
|
||||||
$interface_id = strtolower($interface);
|
$interface_id = strtolower($interface);
|
||||||
|
|
||||||
|
if ($interface_id === 'callable' && $absolute_class === 'Closure') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset(self::$class_implements[$absolute_class][$interface_id])) {
|
if (isset(self::$class_implements[$absolute_class][$interface_id])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,8 @@ class FunctionChecker extends FunctionLikeChecker
|
|||||||
$function_call_arg = $call_args[$function_index];
|
$function_call_arg = $call_args[$function_index];
|
||||||
|
|
||||||
if ($function_call_arg->value instanceof PhpParser\Node\Expr\Closure) {
|
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 (!$closure_return_types) {
|
||||||
if (IssueBuffer::accepts(
|
if (IssueBuffer::accepts(
|
||||||
|
@ -1116,6 +1116,8 @@ class StatementsChecker
|
|||||||
|
|
||||||
$closure_checker->check($use_context, $context->check_methods);
|
$closure_checker->check($use_context, $context->check_methods);
|
||||||
|
|
||||||
|
$stmt->inferredType = Type::getClosure();
|
||||||
|
|
||||||
} elseif ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) {
|
} elseif ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) {
|
||||||
if ($this->checkArrayAccess($stmt, $context, $array_assignment, $assignment_key_type, $assignment_value_type, $assignment_key_value) === false) {
|
if ($this->checkArrayAccess($stmt, $context, $array_assignment, $assignment_key_type, $assignment_value_type, $assignment_key_value) === false) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -254,6 +254,14 @@ abstract class Type
|
|||||||
return new Union([$type]);
|
return new Union([$type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Type\Union */
|
||||||
|
public static function getClosure()
|
||||||
|
{
|
||||||
|
$type = new Atomic('Closure');
|
||||||
|
|
||||||
|
return new Union([$type]);
|
||||||
|
}
|
||||||
|
|
||||||
/** @return Type\Union */
|
/** @return Type\Union */
|
||||||
public static function getArray()
|
public static function getArray()
|
||||||
{
|
{
|
||||||
|
@ -153,10 +153,10 @@ class Php70Test extends PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testGeneratorWithReturn()
|
public function testGeneratorWithReturn()
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('Not yet supported');
|
|
||||||
$stmts = self::$_parser->parse('<?php
|
$stmts = self::$_parser->parse('<?php
|
||||||
/**
|
/**
|
||||||
* @return array<int,int>
|
* @return Generator<int,int>
|
||||||
|
* @psalm-generator-return string
|
||||||
*/
|
*/
|
||||||
function foo(int $i) : Generator {
|
function foo(int $i) : Generator {
|
||||||
if ($i === 1) {
|
if ($i === 1) {
|
||||||
@ -170,31 +170,6 @@ class Php70Test extends PHPUnit_Framework_TestCase
|
|||||||
$file_checker = new \Psalm\Checker\FileChecker('somefile.php', $stmts);
|
$file_checker = new \Psalm\Checker\FileChecker('somefile.php', $stmts);
|
||||||
$context = new Context('somefile.php');
|
$context = new Context('somefile.php');
|
||||||
$file_checker->check(true, true, $context);
|
$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()
|
public function testGeneratorDelegation()
|
||||||
@ -202,6 +177,7 @@ class Php70Test extends PHPUnit_Framework_TestCase
|
|||||||
$stmts = self::$_parser->parse('<?php
|
$stmts = self::$_parser->parse('<?php
|
||||||
/**
|
/**
|
||||||
* @return Generator<int,int>
|
* @return Generator<int,int>
|
||||||
|
* @psalm-generator-return int
|
||||||
*/
|
*/
|
||||||
function count_to_ten() : Generator {
|
function count_to_ten() : Generator {
|
||||||
yield 1;
|
yield 1;
|
||||||
@ -229,6 +205,7 @@ class Php70Test extends PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Generator<int,int>
|
* @return Generator<int,int>
|
||||||
|
* @psalm-generator-return int
|
||||||
*/
|
*/
|
||||||
function nine_ten() : Generator {
|
function nine_ten() : Generator {
|
||||||
yield 9;
|
yield 9;
|
||||||
|
Loading…
Reference in New Issue
Block a user