Skip to content

Commit

Permalink
Prevent redundant messages about missing iterable types in conditiona…
Browse files Browse the repository at this point in the history
…l target/subject
  • Loading branch information
rvanvelzen authored and ondrejmirtes committed May 15, 2022
1 parent 4d584d1 commit 21e9087
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 6 deletions.
12 changes: 12 additions & 0 deletions src/Rules/MissingTypehintCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Accessory\AccessoryType;
use PHPStan\Type\CallableType;
use PHPStan\Type\ConditionalType;
use PHPStan\Type\ConditionalTypeForParameter;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeHelper;
Expand All @@ -21,6 +23,7 @@
use PHPStan\Type\TypeWithClassName;
use Traversable;
use function array_keys;
use function array_merge;
use function in_array;
use function sprintf;

Expand Down Expand Up @@ -71,6 +74,15 @@ public function getIterableTypesWithMissingValueTypehint(Type $type): array
if ($type instanceof AccessoryType) {
return $type;
}
if ($type instanceof ConditionalType || $type instanceof ConditionalTypeForParameter) {
$iterablesWithMissingValueTypehint = array_merge(
$iterablesWithMissingValueTypehint,
$this->getIterableTypesWithMissingValueTypehint($type->getIf()),
$this->getIterableTypesWithMissingValueTypehint($type->getElse()),
);

return $type;
}
if ($type->isIterable()->yes()) {
$iterableValue = $type->getIterableValueType();
if ($iterableValue instanceof MixedType && !$iterableValue->isExplicitMixed()) {
Expand Down
10 changes: 10 additions & 0 deletions src/Type/ConditionalType.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ public function getTarget(): Type
return $this->target;
}

public function getIf(): Type
{
return $this->if;
}

public function getElse(): Type
{
return $this->else;
}

public function isNegated(): bool
{
return $this->negated;
Expand Down
10 changes: 10 additions & 0 deletions src/Type/ConditionalTypeForParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ public function getTarget(): Type
return $this->target;
}

public function getIf(): Type
{
return $this->if;
}

public function getElse(): Type
{
return $this->else;
}

public function isNegated(): bool
{
return $this->negated;
Expand Down
16 changes: 10 additions & 6 deletions tests/PHPStan/Analyser/AnalyserIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -602,15 +602,13 @@ public function testBug6896(): void
}

$errors = $this->runAnalyse(__DIR__ . '/data/bug-6896.php');
$this->assertCount(4, $errors);
$this->assertCount(3, $errors);
$this->assertSame('Generic type IteratorIterator<(int|string), mixed> in PHPDoc tag @return does not specify all template types of class IteratorIterator: TKey, TValue, TIterator', $errors[0]->getMessage());
$this->assertSame(38, $errors[0]->getLine());
$this->assertSame('Method Bug6896\RandHelper::getPseudoRandomWithUrl() return type has no value type specified in iterable type array.', $errors[1]->getMessage());
$this->assertSame('Method Bug6896\RandHelper::getPseudoRandomWithUrl() return type with generic class Bug6896\XIterator does not specify its types: TKey, TValue', $errors[1]->getMessage());
$this->assertSame(38, $errors[1]->getLine());
$this->assertSame('Method Bug6896\RandHelper::getPseudoRandomWithUrl() return type with generic class Bug6896\XIterator does not specify its types: TKey, TValue', $errors[2]->getMessage());
$this->assertSame(38, $errors[2]->getLine());
$this->assertSame('Method Bug6896\RandHelper::getPseudoRandomWithUrl() should return array<TRandKey of (int|string), TRandVal>|Bug6896\XIterator<TRandKey of (int|string), TRandVal>|(iterable<TRandKey of (int|string), TRandVal>&LimitIterator)|IteratorIterator<TRandKey of (int|string), TRandVal> but returns TRandList of array<TRandKey of (int|string), TRandVal>|Traversable<TRandKey of (int|string), TRandVal>.', $errors[3]->getMessage());
$this->assertSame(42, $errors[3]->getLine());
$this->assertSame('Method Bug6896\RandHelper::getPseudoRandomWithUrl() should return array<TRandKey of (int|string), TRandVal>|Bug6896\XIterator<TRandKey of (int|string), TRandVal>|(iterable<TRandKey of (int|string), TRandVal>&LimitIterator)|IteratorIterator<TRandKey of (int|string), TRandVal> but returns TRandList of array<TRandKey of (int|string), TRandVal>|Traversable<TRandKey of (int|string), TRandVal>.', $errors[2]->getMessage());
$this->assertSame(42, $errors[2]->getLine());
}

public function testBug6940(): void
Expand Down Expand Up @@ -773,6 +771,12 @@ public function testBug7214(): void
$this->assertSame(6, $errors[0]->getLine());
}

public function testBug7215(): void
{
$errors = $this->runAnalyse(__DIR__ . '/data/bug-7215.php');
$this->assertNoErrors($errors);
}

/**
* @param string[]|null $allAnalysedFiles
* @return Error[]
Expand Down
26 changes: 26 additions & 0 deletions tests/PHPStan/Analyser/data/bug-7215.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

namespace Bug7215;

use function PHPStan\Testing\assertType;

/**
* @template T
* @param array<T,mixed> $array
* @return (T is int ? ($array is non-empty-array ? non-empty-list<numeric-string> : list<numeric-string>) : ($array is non-empty-array ? non-empty-list<numeric-string> : list<string>))
*/
function keysAsString(array $array): array
{
$keys = [];

foreach ($array as $k => $_) {
$keys[] = (string)$k;
}

return $keys;
}

function () {
assertType('array<int, numeric-string>', keysAsString([]));
assertType('non-empty-array<int, numeric-string>', keysAsString(['' => '']));
};

0 comments on commit 21e9087

Please sign in to comment.