Skip to content

Commit 265d444

Browse files
Improve array_search inference
1 parent 05898b0 commit 265d444

19 files changed

+67
-46
lines changed

src/Type/Accessory/AccessoryArrayListType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
221221
return new MixedType();
222222
}
223223

224-
public function searchArray(Type $needleType): Type
224+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
225225
{
226226
return new MixedType();
227227
}

src/Type/Accessory/HasOffsetValueType.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,16 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
254254
return new NonEmptyArrayType();
255255
}
256256

257-
public function searchArray(Type $needleType): Type
257+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
258258
{
259+
$strict ??= TrinaryLogic::createMaybe();
259260
if (
260261
$needleType instanceof ConstantScalarType && $this->valueType instanceof ConstantScalarType
261-
&& $needleType->getValue() === $this->valueType->getValue()
262+
&& (
263+
$needleType->getValue() === $this->valueType->getValue()
264+
// @phpstan-ignore equal.notAllowed
265+
|| ($strict->no() && $needleType->getValue() == $this->valueType->getValue()) // phpcs:ignore
266+
)
262267
) {
263268
return new UnionType([
264269
new IntegerType(),

src/Type/Accessory/NonEmptyArrayType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
204204
return $this;
205205
}
206206

207-
public function searchArray(Type $needleType): Type
207+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
208208
{
209209
return new MixedType();
210210
}

src/Type/Accessory/OversizedArrayType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
199199
return $this;
200200
}
201201

202-
public function searchArray(Type $needleType): Type
202+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
203203
{
204204
return new MixedType();
205205
}

src/Type/ArrayType.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,13 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
434434
return $this;
435435
}
436436

437-
public function searchArray(Type $needleType): Type
437+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
438438
{
439+
$strict ??= TrinaryLogic::createMaybe();
440+
if ($strict->yes() && $this->getIterableValueType()->isSuperTypeOf($needleType)->no()) {
441+
return new ConstantBooleanType(false);
442+
}
443+
439444
return TypeCombinator::union($this->getIterableKeyType(), new ConstantBooleanType(false));
440445
}
441446

src/Type/Constant/ConstantArrayType.php

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -874,22 +874,32 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
874874
return $builder->getArray();
875875
}
876876

877-
public function searchArray(Type $needleType): Type
877+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
878878
{
879+
$strict ??= TrinaryLogic::createMaybe();
879880
$matches = [];
880881
$hasIdenticalValue = false;
881882

882883
foreach ($this->valueTypes as $index => $valueType) {
883-
$isNeedleSuperType = $valueType->isSuperTypeOf($needleType);
884-
if ($isNeedleSuperType->no()) {
885-
continue;
884+
if ($strict->yes()) {
885+
$isNeedleSuperType = $valueType->isSuperTypeOf($needleType);
886+
if ($isNeedleSuperType->no()) {
887+
continue;
888+
}
886889
}
887890

888-
if ($needleType instanceof ConstantScalarType && $valueType instanceof ConstantScalarType
889-
&& $needleType->getValue() === $valueType->getValue()
890-
&& !$this->isOptionalKey($index)
891-
) {
892-
$hasIdenticalValue = true;
891+
if ($needleType instanceof ConstantScalarType && $valueType instanceof ConstantScalarType) {
892+
// @phpstan-ignore equal.notAllowed
893+
$isLooseEqual = $needleType->getValue() == $valueType->getValue(); // phpcs:ignore
894+
if (!$isLooseEqual) {
895+
continue;
896+
}
897+
if (
898+
($strict->no() || $needleType->getValue() === $valueType->getValue())
899+
&& !$this->isOptionalKey($index)
900+
) {
901+
$hasIdenticalValue = true;
902+
}
893903
}
894904

895905
$matches[] = $this->keyTypes[$index];

src/Type/IntersectionType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -895,9 +895,9 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
895895
return $this->intersectTypes(static fn (Type $type): Type => $type->reverseArray($preserveKeys));
896896
}
897897

898-
public function searchArray(Type $needleType): Type
898+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
899899
{
900-
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType));
900+
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType, $strict));
901901
}
902902

903903
public function shiftArray(): Type

src/Type/MixedType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
257257
return new ArrayType(new MixedType($this->isExplicitMixed), new MixedType($this->isExplicitMixed));
258258
}
259259

260-
public function searchArray(Type $needleType): Type
260+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
261261
{
262262
if ($this->isArray()->no()) {
263263
return new ErrorType();

src/Type/NeverType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
318318
return new NeverType();
319319
}
320320

321-
public function searchArray(Type $needleType): Type
321+
public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
322322
{
323323
return new NeverType();
324324
}

src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use PHPStan\Type\NeverType;
1313
use PHPStan\Type\NullType;
1414
use PHPStan\Type\Type;
15-
use PHPStan\Type\TypeCombinator;
1615
use function count;
1716

1817
#[AutowiredService]
@@ -41,20 +40,14 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
4140
}
4241

4342
if ($argsCount < 3) {
44-
return TypeCombinator::union($haystackArgType->getIterableKeyType(), new ConstantBooleanType(false));
45-
}
46-
47-
$strictArgType = $scope->getType($functionCall->getArgs()[2]->value);
48-
if (!$strictArgType->isTrue()->yes()) {
49-
return TypeCombinator::union($haystackArgType->getIterableKeyType(), new ConstantBooleanType(false));
43+
$strictArgType = new ConstantBooleanType(false);
44+
} else {
45+
$strictArgType = $scope->getType($functionCall->getArgs()[2]->value);
5046
}
5147

5248
$needleArgType = $scope->getType($functionCall->getArgs()[0]->value);
53-
if ($haystackArgType->getIterableValueType()->isSuperTypeOf($needleArgType)->no()) {
54-
return new ConstantBooleanType(false);
55-
}
5649

57-
return $haystackArgType->searchArray($needleArgType);
50+
return $haystackArgType->searchArray($needleArgType, $strictArgType->isTrue());
5851
}
5952

6053
}

0 commit comments

Comments
 (0)