Skip to content

Commit da0539b

Browse files
Improve array_search inference
1 parent 8b38448 commit da0539b

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
@@ -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): Type
225225
{
226226
return new MixedType();
227227
}

src/Type/Accessory/HasOffsetValueType.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,15 @@ 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): Type
258258
{
259259
if (
260260
$needleType instanceof ConstantScalarType && $this->valueType instanceof ConstantScalarType
261-
&& $needleType->getValue() === $this->valueType->getValue()
261+
&& (
262+
$needleType->getValue() === $this->valueType->getValue()
263+
// @phpstan-ignore equal.notAllowed
264+
|| ($strict->no() && $needleType->getValue() == $this->valueType->getValue()) // phpcs:ignore
265+
)
262266
) {
263267
return new UnionType([
264268
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): 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): Type
203203
{
204204
return new MixedType();
205205
}

src/Type/ArrayType.php

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

433-
public function searchArray(Type $needleType): Type
433+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
434434
{
435+
if ($strict->yes() && $this->getIterableValueType()->isSuperTypeOf($needleType)->no()) {
436+
return new ConstantBooleanType(false);
437+
}
438+
435439
return TypeCombinator::union($this->getIterableKeyType(), new ConstantBooleanType(false));
436440
}
437441

src/Type/Constant/ConstantArrayType.php

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -874,22 +874,31 @@ 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): Type
878878
{
879879
$matches = [];
880880
$hasIdenticalValue = false;
881881

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

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

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

src/Type/IntersectionType.php

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

894-
public function searchArray(Type $needleType): Type
894+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
895895
{
896-
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType));
896+
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType, $strict));
897897
}
898898

899899
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): 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): 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)