Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -2520,6 +2520,38 @@
);
}

// For falsey context with unions of multiple constant arrays, directly
// filter union members by size to avoid TypeCombinator::remove issues
// where array types have supertype relationships (e.g. array{mixed} is
// a supertype of array{mixed, string|null, mixed}, causing remove to
// incorrectly eliminate all union members)
$arrays = $argType->getArrays();
if (
$context->falsey()

Check warning on line 2530 in src/Analyser/TypeSpecifier.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrueTruthyFalseFalseyTypeSpecifierContextMutator": @@ @@ // incorrectly eliminate all union members) $arrays = $argType->getArrays(); if ( - $context->falsey() + $context->false() && count($arrays) > 1 && $argType->isConstantArray()->yes() && $rightType->isInteger()->yes()

Check warning on line 2530 in src/Analyser/TypeSpecifier.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrueTruthyFalseFalseyTypeSpecifierContextMutator": @@ @@ // incorrectly eliminate all union members) $arrays = $argType->getArrays(); if ( - $context->falsey() + $context->false() && count($arrays) > 1 && $argType->isConstantArray()->yes() && $rightType->isInteger()->yes()
&& count($arrays) > 1
&& $argType->isConstantArray()->yes()

Check warning on line 2532 in src/Analyser/TypeSpecifier.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ if ( $context->falsey() && count($arrays) > 1 - && $argType->isConstantArray()->yes() + && !$argType->isConstantArray()->no() && $rightType->isInteger()->yes() && $this->isNormalCountCall($unwrappedLeftExpr, $argType, $scope)->yes() ) {

Check warning on line 2532 in src/Analyser/TypeSpecifier.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ if ( $context->falsey() && count($arrays) > 1 - && $argType->isConstantArray()->yes() + && !$argType->isConstantArray()->no() && $rightType->isInteger()->yes() && $this->isNormalCountCall($unwrappedLeftExpr, $argType, $scope)->yes() ) {
&& $rightType->isInteger()->yes()
&& $this->isNormalCountCall($unwrappedLeftExpr, $argType, $scope)->yes()
) {
$result = [];
foreach ($arrays as $innerType) {
$arraySize = $innerType->getArraySize();
$isSize = $rightType->isSuperTypeOf($arraySize);
if ($isSize->yes()) {
continue;
}

$result[] = $innerType;
}

if (count($result) > 0) {
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
return $funcTypes->unionWith(
$this->create($unwrappedLeftExpr->getArgs()[0]->value, TypeCombinator::union(...$result), TypeSpecifierContext::createTrue(), $scope)->setAlwaysOverwriteTypes()->setRootExpr($expr),
);
}
}

$specifiedTypes = $this->specifyTypesForCountFuncCall($unwrappedLeftExpr, $argType, $rightType, $context, $scope, $expr);
if ($specifiedTypes !== null) {
return $specifiedTypes;
Expand Down
24 changes: 24 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-11488.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types = 1);

namespace Bug11488;

use function PHPStan\Testing\assertType;

class Foo
{
/**
* @param array{mixed}|array{mixed, string|null, mixed} $row
*/
protected function test(array $row): string
{
if (count($row) !== 1) {
assertType('array{mixed, string|null, mixed}', $row);

[$field, $operator, $value] = $row;
assertType('string|null', $operator);
return $operator ?? '=';
}

return '';
}
}
Loading