Skip to content

Commit b705639

Browse files
Improve array_search inference
1 parent 80d8fc6 commit b705639

19 files changed

+64
-46
lines changed

src/Type/Accessory/AccessoryArrayListType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
241241
return new MixedType();
242242
}
243243

244-
public function searchArray(Type $needleType): Type
244+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
245245
{
246246
return new MixedType();
247247
}

src/Type/Accessory/HasOffsetValueType.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,15 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
262262
return new NonEmptyArrayType();
263263
}
264264

265-
public function searchArray(Type $needleType): Type
265+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
266266
{
267267
if (
268268
$needleType instanceof ConstantScalarType && $this->valueType instanceof ConstantScalarType
269-
&& $needleType->getValue() === $this->valueType->getValue()
269+
&& (
270+
$needleType->getValue() === $this->valueType->getValue()
271+
// @phpstan-ignore equal.notAllowed
272+
|| ($strict->no() && $needleType->getValue() == $this->valueType->getValue()) // phpcs:ignore
273+
)
270274
) {
271275
return new UnionType([
272276
new IntegerType(),

src/Type/Accessory/NonEmptyArrayType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
218218
return $this;
219219
}
220220

221-
public function searchArray(Type $needleType): Type
221+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
222222
{
223223
return new MixedType();
224224
}

src/Type/Accessory/OversizedArrayType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
214214
return $this;
215215
}
216216

217-
public function searchArray(Type $needleType): Type
217+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
218218
{
219219
return new MixedType();
220220
}

src/Type/ArrayType.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,12 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
601601
return $this;
602602
}
603603

604-
public function searchArray(Type $needleType): Type
604+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
605605
{
606+
if ($strict->yes() && $this->getIterableValueType()->isSuperTypeOf($needleType)->no()) {
607+
return new ConstantBooleanType(false);
608+
}
609+
606610
return TypeCombinator::union($this->getIterableKeyType(), new ConstantBooleanType(false));
607611
}
608612

src/Type/Constant/ConstantArrayType.php

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -909,22 +909,31 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
909909
return $builder->getArray();
910910
}
911911

912-
public function searchArray(Type $needleType): Type
912+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
913913
{
914914
$matches = [];
915915
$hasIdenticalValue = false;
916916

917917
foreach ($this->valueTypes as $index => $valueType) {
918-
$isNeedleSuperType = $valueType->isSuperTypeOf($needleType);
919-
if ($isNeedleSuperType->no()) {
920-
continue;
918+
if ($strict->yes()) {
919+
$isNeedleSuperType = $valueType->isSuperTypeOf($needleType);
920+
if ($isNeedleSuperType->no()) {
921+
continue;
922+
}
921923
}
922924

923-
if ($needleType instanceof ConstantScalarType && $valueType instanceof ConstantScalarType
924-
&& $needleType->getValue() === $valueType->getValue()
925-
&& !$this->isOptionalKey($index)
926-
) {
927-
$hasIdenticalValue = true;
925+
if ($needleType instanceof ConstantScalarType && $valueType instanceof ConstantScalarType) {
926+
// @phpstan-ignore equal.notAllowed
927+
$isLooseEqual = $needleType->getValue() == $valueType->getValue(); // phpcs:ignore
928+
if (!$isLooseEqual) {
929+
continue;
930+
}
931+
if (
932+
($strict->no() || $needleType->getValue() === $valueType->getValue())
933+
&& !$this->isOptionalKey($index)
934+
) {
935+
$hasIdenticalValue = true;
936+
}
928937
}
929938

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

src/Type/IntersectionType.php

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

822-
public function searchArray(Type $needleType): Type
822+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
823823
{
824-
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType));
824+
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType, $strict));
825825
}
826826

827827
public function shiftArray(): Type

src/Type/MixedType.php

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

267-
public function searchArray(Type $needleType): Type
267+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
268268
{
269269
if ($this->isArray()->no()) {
270270
return new ErrorType();

src/Type/NeverType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
336336
return new NeverType();
337337
}
338338

339-
public function searchArray(Type $needleType): Type
339+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
340340
{
341341
return new NeverType();
342342
}

src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php

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

1716
final class ArraySearchFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
@@ -39,20 +38,14 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
3938
}
4039

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

5046
$needleArgType = $scope->getType($functionCall->getArgs()[0]->value);
51-
if ($haystackArgType->getIterableValueType()->isSuperTypeOf($needleArgType)->no()) {
52-
return new ConstantBooleanType(false);
53-
}
5447

55-
return $haystackArgType->searchArray($needleArgType);
48+
return $haystackArgType->searchArray($needleArgType, $strictArgType->isTrue());
5649
}
5750

5851
}

0 commit comments

Comments
 (0)