fix return type for yield from (#4066)

This commit is contained in:
Tomas Votruba 2020-08-30 08:57:43 +02:00 committed by GitHub
parent f8b485305f
commit 7312185dc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 16 deletions

View File

@ -6,8 +6,10 @@ namespace Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Iterator;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\Expr\YieldFrom;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
@ -41,23 +43,26 @@ final class YieldNodesReturnTypeInferer extends AbstractTypeInferer implements R
{
$yieldNodes = $this->findCurrentScopeYieldNodes($functionLike);
if (count($yieldNodes) === 0) {
return new MixedType();
}
$types = [];
if (count($yieldNodes) > 0) {
foreach ($yieldNodes as $yieldNode) {
if ($yieldNode->value === null) {
continue;
}
$yieldValueStaticType = $this->nodeTypeResolver->getStaticType($yieldNode->value);
$types[] = new ArrayType(new MixedType(), $yieldValueStaticType);
foreach ($yieldNodes as $yieldNode) {
$value = $this->resolveYieldValue($yieldNode);
if ($value === null) {
continue;
}
if ($this->phpVersionProvider->isAtLeast(PhpVersionFeature::ITERABLE_TYPE)) {
// @see https://www.php.net/manual/en/language.types.iterable.php
$types[] = new IterableType(new MixedType(), new MixedType());
} else {
$types[] = new ObjectType(Iterator::class);
}
$yieldValueStaticType = $this->nodeTypeResolver->getStaticType($value);
$types[] = new ArrayType(new MixedType(), $yieldValueStaticType);
}
if ($this->phpVersionProvider->isAtLeast(PhpVersionFeature::ITERABLE_TYPE)) {
// @see https://www.php.net/manual/en/language.types.iterable.php
$types[] = new IterableType(new MixedType(), new MixedType());
} else {
$types[] = new ObjectType(Iterator::class);
}
return $this->typeFactory->createMixedPassedOrUnionType($types);
@ -69,7 +74,7 @@ final class YieldNodesReturnTypeInferer extends AbstractTypeInferer implements R
}
/**
* @return Yield_[]
* @return array<Yield_|YieldFrom>
*/
private function findCurrentScopeYieldNodes(FunctionLike $functionLike): array
{
@ -83,7 +88,7 @@ final class YieldNodesReturnTypeInferer extends AbstractTypeInferer implements R
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
if (! $node instanceof Yield_) {
if (! $node instanceof Yield_ && ! $node instanceof YieldFrom) {
return null;
}
@ -93,4 +98,16 @@ final class YieldNodesReturnTypeInferer extends AbstractTypeInferer implements R
return $yieldNodes;
}
/**
* @param Yield_|YieldFrom $yieldExpr
*/
private function resolveYieldValue(Expr $yieldExpr): ?Expr
{
if ($yieldExpr instanceof Yield_) {
return $yieldExpr->value;
}
return $yieldExpr->expr;
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
use Generator;
class SkipExplicitGeneratorFrom
{
/**
* @return Generator<string, string>
*/
public function run(string $part): Generator
{
$result = ['a'];
parse_str($part, $result);
yield from $result;
}
}