Skip to content

Commit 264f473

Browse files
phpstan-botclaude
andcommitted
Refactor: extract computeGuaranteedValueType private method
Extract the narrowing value type computation for the !in_array false context into a dedicated private method for better readability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d3513ec commit 264f473

File tree

1 file changed

+37
-31
lines changed

1 file changed

+37
-31
lines changed

src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PHPStan\Type\FunctionTypeSpecifyingExtension;
2020
use PHPStan\Type\MixedType;
2121
use PHPStan\Type\NeverType;
22+
use PHPStan\Type\Type;
2223
use PHPStan\Type\TypeCombinator;
2324
use PHPStan\Type\UnionType;
2425
use function count;
@@ -135,37 +136,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
135136
&& count($needleType->getFiniteTypes()) > 0
136137
&& $arrayType->isIterableAtLeastOnce()->yes()
137138
) {
138-
// In false context (!in_array), we can only remove values guaranteed
139-
// to be in every possible array variant. For union types like
140-
// array{A}|array{B}, getIterableValueType() returns A|B but neither
141-
// value is guaranteed to be in every variant.
142-
$innerTypes = $arrayType instanceof UnionType ? $arrayType->getTypes() : [$arrayType];
143-
$innerValueTypes = [];
144-
foreach ($innerTypes as $innerType) {
145-
$constantArrays = $innerType->getConstantArrays();
146-
if (count($constantArrays) > 0) {
147-
// Only include values from non-optional keys, since optional
148-
// keys may not be present in the array at runtime.
149-
$perArrayTypes = [];
150-
foreach ($constantArrays as $constantArray) {
151-
$guaranteedTypes = [];
152-
foreach ($constantArray->getValueTypes() as $i => $valueType) {
153-
if (!$constantArray->isOptionalKey($i)) {
154-
$guaranteedTypes[] = $valueType;
155-
}
156-
}
157-
$perArrayTypes[] = count($guaranteedTypes) > 0
158-
? TypeCombinator::union(...$guaranteedTypes)
159-
: new NeverType();
160-
}
161-
$innerValueTypes[] = TypeCombinator::intersect(...$perArrayTypes);
162-
} else {
163-
$innerValueTypes[] = $innerType->getIterableValueType();
164-
}
165-
}
166-
$narrowingValueType = count($innerValueTypes) > 0
167-
? TypeCombinator::intersect(...$innerValueTypes)
168-
: $arrayValueType;
139+
$narrowingValueType = $this->computeGuaranteedValueType($arrayType, $arrayValueType);
169140
if (count($narrowingValueType->getFiniteTypes()) > 0) {
170141
$specifiedTypes = $this->typeSpecifier->create(
171142
$needleExpr,
@@ -217,4 +188,39 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
217188
return $specifiedTypes;
218189
}
219190

191+
/**
192+
* Computes the type of values guaranteed to be in every possible variant
193+
* of the array. For union types like array{A}|array{B}, we intersect the
194+
* value types so only values present in all variants are used for narrowing.
195+
*/
196+
private function computeGuaranteedValueType(Type $arrayType, Type $arrayValueType): Type
197+
{
198+
$innerTypes = $arrayType instanceof UnionType ? $arrayType->getTypes() : [$arrayType];
199+
$innerValueTypes = [];
200+
foreach ($innerTypes as $innerType) {
201+
$constantArrays = $innerType->getConstantArrays();
202+
if (count($constantArrays) > 0) {
203+
$perArrayTypes = [];
204+
foreach ($constantArrays as $constantArray) {
205+
$guaranteedTypes = [];
206+
foreach ($constantArray->getValueTypes() as $i => $valueType) {
207+
if (!$constantArray->isOptionalKey($i)) {
208+
$guaranteedTypes[] = $valueType;
209+
}
210+
}
211+
$perArrayTypes[] = count($guaranteedTypes) > 0
212+
? TypeCombinator::union(...$guaranteedTypes)
213+
: new NeverType();
214+
}
215+
$innerValueTypes[] = TypeCombinator::intersect(...$perArrayTypes);
216+
} else {
217+
$innerValueTypes[] = $innerType->getIterableValueType();
218+
}
219+
}
220+
221+
return count($innerValueTypes) > 0
222+
? TypeCombinator::intersect(...$innerValueTypes)
223+
: $arrayValueType;
224+
}
225+
220226
}

0 commit comments

Comments
 (0)