Skip to content

Commit 8b2bf86

Browse files
phpstan-botclaude
andcommitted
Add isObject() guard in ImplicitToStringCallHelper for constant scalar intersections
The TypeCombinator narrowing excludes constant scalar values (0, '', '0', false, 0.0) because TemplateTypeFactory can't create proper template types for all of them. This means types like `false&T` and `0.0&T` remain as intersections where MixedType::hasMethod('__toString') returns Yes, causing false positive purity errors. Add an early return in ImplicitToStringCallHelper when isObject()->no() to handle these remaining cases. Since __toString() can only be called on objects, non-object types always use PHP's built-in string conversion. Add test cases using empty() + !\is_array() which narrows to constant scalar falsy values. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 13c22db commit 8b2bf86

3 files changed

Lines changed: 34 additions & 0 deletions

File tree

src/Analyser/ExprHandler/Helper/ImplicitToStringCallHelper.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ public function processImplicitToStringCall(Expr $expr, MutatingScope $scope): E
2828
$impurePoints = [];
2929

3030
$exprType = $scope->getType($expr);
31+
if ($exprType->isObject()->no()) {
32+
return new ExpressionResult(
33+
$scope,
34+
hasYield: false,
35+
isAlwaysTerminating: false,
36+
throwPoints: [],
37+
impurePoints: [],
38+
);
39+
}
3140
$toStringMethod = $scope->getMethodReflection($exprType, '__toString');
3241
if ($toStringMethod === null) {
3342
return new ExpressionResult(

tests/PHPStan/Rules/Pure/data/bug-14511-method.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,17 @@ public function testStringConcat(mixed $val): ?string
3131
return null;
3232
}
3333

34+
/**
35+
* @phpstan-pure
36+
* @template T of mixed
37+
* @param T $val
38+
*/
39+
public function testEmptyNonArray(mixed $val): ?string
40+
{
41+
if (empty($val) && !\is_array($val)) {
42+
return (string) $val;
43+
}
44+
return null;
45+
}
46+
3447
}

tests/PHPStan/Rules/Pure/data/bug-14511.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,15 @@ function testStringVal(mixed $val): ?string {
6161
}
6262
return null;
6363
}
64+
65+
/**
66+
* @phpstan-pure
67+
* @template T of mixed
68+
* @param T $val
69+
*/
70+
function testEmptyNonArray(mixed $val): ?string {
71+
if (empty($val) && !\is_array($val)) {
72+
return (string) $val;
73+
}
74+
return null;
75+
}

0 commit comments

Comments
 (0)