Skip to content

Commit

Permalink
CallableType and ClosureType::describe() - use phpdoc-parser Printer …
Browse files Browse the repository at this point in the history
…for better precision
  • Loading branch information
ondrejmirtes committed May 17, 2023
1 parent 413079d commit 30f60c1
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 47 deletions.
35 changes: 20 additions & 15 deletions src/Type/CallableType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\PhpDocParser\Printer\Printer;
use PHPStan\Reflection\ClassMemberAccessAnswerer;
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\PassedByReference;
use PHPStan\Reflection\Php\DummyParameter;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Generic\TemplateType;
Expand All @@ -29,8 +32,6 @@
use function array_map;
use function array_merge;
use function count;
use function implode;
use function sprintf;

/** @api */
class CallableType implements CompoundType, ParametersAcceptor
Expand Down Expand Up @@ -176,19 +177,23 @@ public function describe(VerbosityLevel $level): string
{
return $level->handle(
static fn (): string => 'callable',
fn (): string => sprintf(
'callable(%s): %s',
implode(', ', array_map(
static fn (ParameterReflection $param): string => sprintf(
'%s%s%s',
$param->isVariadic() ? '...' : '',
$param->getType()->describe($level),
$param->isOptional() && !$param->isVariadic() ? '=' : '',
),
$this->getParameters(),
)),
$this->returnType->describe($level),
),
function (): string {
$printer = new Printer();
$selfWithoutParameterNames = new self(
array_map(static fn (ParameterReflection $p): ParameterReflection => new DummyParameter(

This comment has been minimized.

Copy link
@mvorisek

mvorisek May 17, 2023

Contributor

phpstan/phpstan#9009 (comment) $this should be always dumped with the class name as when $this is dumped normally

This comment has been minimized.

Copy link
@mvorisek

mvorisek May 18, 2023

Contributor

also float must be always dumped with decimal . to stress it it float and not int - https://phpstan.org/r/d2c9c607-a105-46f1-8c71-f3f136a56ce3

'',
$p->getType(),
$p->isOptional() && !$p->isVariadic(),
PassedByReference::createNo(),
$p->isVariadic(),
$p->getDefaultValue(),
), $this->parameters),
$this->returnType,
$this->variadic,
);

return $printer->print($selfWithoutParameterNames->toPhpDocNode());
},
);
}

Expand Down
37 changes: 22 additions & 15 deletions src/Type/ClosureType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\PhpDocParser\Printer\Printer;
use PHPStan\Reflection\ClassMemberAccessAnswerer;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ConstantReflection;
use PHPStan\Reflection\ExtendedMethodReflection;
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\PassedByReference;
use PHPStan\Reflection\Php\ClosureCallUnresolvedMethodPrototypeReflection;
use PHPStan\Reflection\Php\DummyParameter;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection;
use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
Expand All @@ -37,8 +40,6 @@
use function array_map;
use function array_merge;
use function count;
use function implode;
use function sprintf;

/** @api */
class ClosureType implements TypeWithClassName, ParametersAcceptor
Expand Down Expand Up @@ -170,19 +171,25 @@ public function describe(VerbosityLevel $level): string
{
return $level->handle(
static fn (): string => 'Closure',
fn (): string => sprintf(
'Closure(%s): %s',
implode(', ', array_map(
static fn (ParameterReflection $param): string => sprintf(
'%s%s%s',
$param->isVariadic() ? '...' : '',
$param->getType()->describe($level),
$param->isOptional() && !$param->isVariadic() ? '=' : '',
),
$this->parameters,
)),
$this->returnType->describe($level),
),
function (): string {
$printer = new Printer();
$selfWithoutParameterNames = new self(
array_map(static fn (ParameterReflection $p): ParameterReflection => new DummyParameter(
'',
$p->getType(),
$p->isOptional() && !$p->isVariadic(),
PassedByReference::createNo(),
$p->isVariadic(),
$p->getDefaultValue(),
), $this->parameters),
$this->returnType,
$this->variadic,
$this->templateTypeMap,
$this->resolvedTemplateTypeMap,
);

return $printer->print($selfWithoutParameterNames->toPhpDocNode());
},
);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1412,11 +1412,11 @@ public function dataVarAnnotations(): array
'$callable',
],
[
'callable(int, ...string): void',
'callable(int, string ...): void',
'$callableWithTypes',
],
[
'Closure(int, ...string): void',
'Closure(int, string ...): void',
'$closureWithTypes',
],
[
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/data/generics.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ function f($a, $b)
{
$result = [];
assertType('array<A (function PHPStan\Generics\FunctionsAssertType\f(), argument)>', $a);
assertType('callable(A (function PHPStan\Generics\FunctionsAssertType\f(), argument)): B (function PHPStan\Generics\FunctionsAssertType\f(), argument)', $b);
assertType('callable(A): B', $b);
foreach ($a as $k => $v) {
assertType('A (function PHPStan\Generics\FunctionsAssertType\f(), argument)', $v);
$newV = $b($v);
Expand Down
6 changes: 3 additions & 3 deletions tests/PHPStan/Analyser/data/type-aliases.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ public function globalAlias($parameter)
*/
public function localAlias($parameter)
{
assertType('callable(string): string|false', $parameter);
assertType('callable(string): (string|false)', $parameter);
}

/**
* @param NestedLocalTypeAlias $parameter
*/
public function nestedLocalAlias($parameter)
{
assertType('array<callable(string): string|false>', $parameter);
assertType('array<callable(string): (string|false)>', $parameter);
}

/**
Expand Down Expand Up @@ -151,7 +151,7 @@ public function testIntAlias($int)
}

assertType('int|string', (new Foo)->globalAliasProperty);
assertType('callable(string): string|false', (new Foo)->localAliasProperty);
assertType('callable(string): (string|false)', (new Foo)->localAliasProperty);
assertType('Countable&Traversable', (new Foo)->importedAliasProperty);
assertType('Countable&Traversable', (new Foo)->reexportedAliasProperty);
assertType('TypeAliasesDataset\SubScope\Foo', (new Foo)->scopedAliasProperty);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,12 +554,12 @@ public function testArrayReduceCallback(): void
5,
],
[
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): string|null, Closure(string, int): non-empty-string given.',
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): (string|null), Closure(string, int): non-empty-string given.',
13,
'Type string of parameter #1 $foo of passed callable needs to be same or wider than parameter type string|null of accepting callable.',
],
[
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): string|null, Closure(string, int): non-empty-string given.',
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): (string|null), Closure(string, int): non-empty-string given.',
22,
'Type string of parameter #1 $foo of passed callable needs to be same or wider than parameter type string|null of accepting callable.',
],
Expand All @@ -574,12 +574,12 @@ public function testArrayReduceArrowFunctionCallback(): void
5,
],
[
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): string|null, Closure(string, int): non-empty-string given.',
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): (string|null), Closure(string, int): non-empty-string given.',
11,
'Type string of parameter #1 $foo of passed callable needs to be same or wider than parameter type string|null of accepting callable.',
],
[
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): string|null, Closure(string, int): non-empty-string given.',
'Parameter #2 $callback of function array_reduce expects callable(string|null, int): (string|null), Closure(string, int): non-empty-string given.',
18,
'Type string of parameter #1 $foo of passed callable needs to be same or wider than parameter type string|null of accepting callable.',
],
Expand Down Expand Up @@ -910,7 +910,7 @@ public function testBug2782(): void
{
$this->analyse([__DIR__ . '/data/bug-2782.php'], [
[
'Parameter #2 $callback of function usort expects callable(stdClass, stdClass): int, Closure(int, int): -1|1 given.',
'Parameter #2 $callback of function usort expects callable(stdClass, stdClass): int, Closure(int, int): (-1|1) given.',
13,
],
]);
Expand Down
12 changes: 6 additions & 6 deletions tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ public function testCallMethods(): void
'See: https://phpstan.org/blog/solving-phpstan-error-unable-to-resolve-template-type',
],
[
'Parameter #1 $a of method Test\\CallableWithMixedArray::doBar() expects callable(array<string>): array<string>, Closure(array): array{\'foo\'}|null given.',
'Parameter #1 $a of method Test\\CallableWithMixedArray::doBar() expects callable(array<string>): array<string>, Closure(array): (array{\'foo\'}|null) given.',
1533,
],
[
Expand Down Expand Up @@ -791,7 +791,7 @@ public function testCallMethodsOnThisOnly(): void
'See: https://phpstan.org/blog/solving-phpstan-error-unable-to-resolve-template-type',
],
[
'Parameter #1 $a of method Test\\CallableWithMixedArray::doBar() expects callable(array<string>): array<string>, Closure(array): array{\'foo\'}|null given.',
'Parameter #1 $a of method Test\\CallableWithMixedArray::doBar() expects callable(array<string>): array<string>, Closure(array): (array{\'foo\'}|null) given.',
1533,
],
[
Expand Down Expand Up @@ -2781,21 +2781,21 @@ public function dataCallablesWithoutCheckNullables(): iterable

$errors = [
[
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBar() expects callable(float|null): float|null, Closure(float): float given.',
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBar() expects callable(float|null): (float|null), Closure(float): float given.',
25,
'Type float of parameter #1 $f of passed callable needs to be same or wider than parameter type float|null of accepting callable.',
],
[
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBaz() expects Closure(float|null): float|null, Closure(float): float given.',
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBaz() expects Closure(float|null): (float|null), Closure(float): float given.',
28,
'Type float of parameter #1 $f of passed callable needs to be same or wider than parameter type float|null of accepting callable.',
],
[
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBar2() expects callable(float|null): float, Closure(float|null): float|null given.',
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBar2() expects callable(float|null): float, Closure(float|null): (float|null) given.',
32,
],
[
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBaz2() expects Closure(float|null): float, Closure(float|null): float|null given.',
'Parameter #1 $cb of method CallablesWithoutCheckNullables\Foo::doBaz2() expects Closure(float|null): float, Closure(float|null): (float|null) given.',
35,
],
[
Expand Down

0 comments on commit 30f60c1

Please sign in to comment.