Skip to content

Commit

Permalink
Fix wrong tip about returning a list
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Nov 14, 2023
1 parent 7f87272 commit 00adfaa
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 12 deletions.
12 changes: 1 addition & 11 deletions src/Type/Accessory/AccessoryArrayListType.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;
use function sprintf;

/** @api */
class AccessoryArrayListType implements CompoundType, AccessoryType
Expand Down Expand Up @@ -89,17 +88,8 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult

$isArray = $type->isArray();
$isList = $type->isList();
$reasons = [];
if ($isArray->yes() && !$isList->yes()) {
$verbosity = VerbosityLevel::getRecommendedLevelByType($this, $type);
$reasons[] = sprintf(
'%s %s a list.',
$type->describe($verbosity),
$isList->no() ? 'is not' : 'might not be',
);
}

return new AcceptsResult($isArray->and($isList), $reasons);
return new AcceptsResult($isArray->and($isList), []);
}

public function isSuperTypeOf(Type $type): TrinaryLogic
Expand Down
14 changes: 14 additions & 0 deletions src/Type/IntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ public function acceptsWithReason(Type $otherType, bool $strictTypes): AcceptsRe
$result = $result->and($type->acceptsWithReason($otherType, $strictTypes));
}

if (!$result->yes()) {
$isList = $otherType->isList();
if ($this->isList()->yes() && !$isList->yes()) {
$verbosity = VerbosityLevel::getRecommendedLevelByType($this, $otherType);
return new AcceptsResult($result->result, [
sprintf(
'%s %s a list.',
$otherType->describe($verbosity),
$isList->no() ? 'is not' : 'might not be',
),
]);
}
}

return $result;
}

Expand Down
12 changes: 12 additions & 0 deletions tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,16 @@ public function testBug8846(): void
$this->analyse([__DIR__ . '/data/bug-8846.php'], []);
}

public function testBug10077(): void
{
$this->checkExplicitMixed = true;
$this->checkNullables = true;
$this->analyse([__DIR__ . '/data/bug-10077.php'], [
[
'Function Bug10077\mergeMediaQueries() should return list<Bug10077\CssMediaQuery>|null but returns list<Bug10077\MediaQueryMergeResult>.',
56,
],
]);
}

}
57 changes: 57 additions & 0 deletions tests/PHPStan/Rules/Functions/data/bug-10077.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Bug10077;

interface MediaQueryMergeResult
{
}


enum MediaQuerySingletonMergeResult implements MediaQueryMergeResult
{
case empty;
case unrepresentable;
}

// In actual code, this is a final class implementing its methods
abstract class CssMediaQuery implements MediaQueryMergeResult
{
abstract public function merge(CssMediaQuery $other): MediaQueryMergeResult;
}


/**
* Returns a list of queries that selects for contexts that match both
* $queries1 and $queries2.
*
* Returns the empty list if there are no contexts that match both $queries1
* and $queries2, or `null` if there are contexts that can't be represented
* by media queries.
*
* @param CssMediaQuery[] $queries1
* @param CssMediaQuery[] $queries2
*
* @return list<CssMediaQuery>|null
*/
function mergeMediaQueries(array $queries1, array $queries2): ?array
{
$queries = [];

foreach ($queries1 as $query1) {
foreach ($queries2 as $query2) {
$result = $query1->merge($query2);

if ($result === MediaQuerySingletonMergeResult::empty) {
continue;
}

if ($result === MediaQuerySingletonMergeResult::unrepresentable) {
return null;
}

$queries[] = $result;
}
}

return $queries;
}
10 changes: 10 additions & 0 deletions tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -955,4 +955,14 @@ public function testBug9766(): void
$this->analyse([__DIR__ . '/data/bug-9766.php'], []);
}

public function testWrongListTip(): void
{
$this->analyse([__DIR__ . '/data/wrong-list-tip.php'], [
[
'Method WrongListTip\Test::doFoo() should return list<WrongListTip\Foo> but returns list<WrongListTip\Bar>.',
23,
],
]);
}

}
34 changes: 34 additions & 0 deletions tests/PHPStan/Rules/Methods/data/wrong-list-tip.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace WrongListTip;

interface Foo
{

}

interface Bar
{

}

class Test
{

/**
* @return list<Foo>
*/
public function doFoo(): array
{
return $this->listOfBars();
}

/**
* @return list<Bar>
*/
public function listOfBars(): array
{
return [];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ public function testBug3311b(): void
[
'Property Bug3311b\Foo::$bar (list<string>) does not accept non-empty-array<int<0, max>, string>.',
16,
'array<int<0, max>, string> might not be a list.',
'non-empty-array<int<0, max>, string> might not be a list.',
],
]);
}
Expand Down

0 comments on commit 00adfaa

Please sign in to comment.