Skip to content
Open
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
1 change: 0 additions & 1 deletion src/Analyser/ExprHandler/FuncCallHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
if (
$functionReflection !== null
&& $this->rememberPossiblyImpureFunctionValues
&& $parametersAcceptor !== null
&& $functionReflection->hasSideEffects()->maybe()
&& !$functionReflection->isBuiltin()
) {
Expand Down
12 changes: 11 additions & 1 deletion src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -3787,6 +3787,13 @@ private function createConditionalExpressions(
): array
{
$newVariableTypes = $ourExpressionTypes;

// When our-branch type is a subtype of their-branch type, the union
// absorbs it (merged === their). Such a variable is a poor *guard* —
// asserting its our-branch type later wouldn't reliably select this
// branch — but it remains a valid conditional *target*, so only exclude
// it from guard selection instead of dropping it entirely.
$guardsToExclude = [];
foreach ($theirExpressionTypes as $exprString => $holder) {
if (!array_key_exists($exprString, $mergedExpressionTypes)) {
continue;
Expand All @@ -3804,7 +3811,7 @@ private function createConditionalExpressions(
continue;
}

unset($newVariableTypes[$exprString]);
$guardsToExclude[$exprString] = true;
}

$typeGuards = [];
Expand All @@ -3818,6 +3825,9 @@ private function createConditionalExpressions(
if (!$holder->getCertainty()->yes()) {
continue;
}
if (array_key_exists($exprString, $guardsToExclude)) {
continue;
}

if (
array_key_exists($exprString, $theirExpressionTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier):

if ($identifier->isClass()) {
$fetchedClassNode = null;
$fetchedFile = null;
foreach ($files as $file) {
$fetchedClassNodes = $this->fileNodesFetcher->fetchNodes($file)->getClassNodes();

Expand All @@ -121,13 +122,10 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier):

/** @var FetchedNode<Node\Stmt\ClassLike> $fetchedClassNode */
$fetchedClassNode = current($fetchedClassNodes[$identifierName]);
$fetchedFile = $file;
}

if ($fetchedClassNode === null) {
return null;
}

[$reflectionCacheKey, $variableCacheKey] = $this->getCacheKeys($file, $identifier);
[$reflectionCacheKey, $variableCacheKey] = $this->getCacheKeys($fetchedFile, $identifier);
$classReflection = $this->nodeToReflection($reflector, $fetchedClassNode);
$this->cache->save($reflectionCacheKey, $variableCacheKey, $classReflection->exportToCache());

Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug-5051.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function testWithBooleans($data): void

if ($update) {
assertType('10', $data);
assertType('bool', $foo);
assertType('true', $foo);
} else {
assertType('1|2|3', $data);
assertType('bool', $foo);
Expand Down
71 changes: 71 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-7948.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php declare(strict_types = 1);

namespace Bug7948;

use function PHPStan\Testing\assertType;

class HelloWorld
{
/**
* @param string|array<string, mixed> $name
* @param mixed $value
*/
public function testMixed($name, $value): void
{
if (is_array($name)) {
$value = null;
}

if (is_array($name)) {
assertType('null', $value);
}
}

/**
* @param string|array<string, mixed> $name
* @param int $value
*/
public function testInt($name, $value): void
{
if (is_array($name)) {
$value = null;
}

if (is_array($name)) {
assertType('null', $value);
}
}

/**
* Assigned value (5) is a subtype of the original type (int|string),
* so the merged type absorbs it just like null|mixed does.
*
* @param string|array<string, mixed> $name
* @param int|string $value
*/
public function testSubtype($name, $value): void
{
if (is_array($name)) {
$value = 5;
}

if (is_array($name)) {
assertType('5', $value);
}
}

/**
* @param string|array<string, mixed> $name
* @param mixed $value
*/
public function testMixedNegated($name, $value): void
{
if (!is_array($name)) {
$value = null;
}

if (!is_array($name)) {
assertType('null', $value);
}
}
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug-8467b.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function foo (?string $cwd, bool $initialClone = false): void {

if ($initialClone && isset($origCwd)) {
assertType('string', $origCwd);
assertType('string|null', $cwd); // could be null
assertType('null', $cwd);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public function variants(string $s) {
assertType('string', $s);

if (strpos($s, ':') === 5) {
assertType('string', $s); // could be non-empty-string
assertType('non-falsy-string', $s);
}
assertType('string', $s);
if (strpos($s, ':') !== 5) {
Expand Down Expand Up @@ -164,7 +164,7 @@ public function variants(string $s) {
assertType('string', $s);

if (mb_strpos($s, ':') === 5) {
assertType('string', $s); // could be non-empty-string
assertType('non-falsy-string', $s);
}
assertType('string', $s);
if (mb_strpos($s, ':') !== 5) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,6 @@ public function testTypesAssignedToPropertiesExpressionNames(): void
'Property PropertiesFromArrayIntoObject\Foo::$lall (int) does not accept string.',
69,
],
[
'Property PropertiesFromArrayIntoObject\Foo::$foo (string) does not accept float.',
Comment thread
VincentLanglet marked this conversation as resolved.
83,
],
[
'Property PropertiesFromArrayIntoObject\Foo::$foo (string) does not accept float|int|string.',
97,
Expand Down
Loading