Skip to content

Commit 8e55d6d

Browse files
Improve array_search inference
1 parent 1036203 commit 8e55d6d

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
@@ -225,7 +225,7 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
225225
return new MixedType();
226226
}
227227

228-
public function searchArray(Type $needleType): Type
228+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
229229
{
230230
return new MixedType();
231231
}

src/Type/Accessory/HasOffsetValueType.php

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

253-
public function searchArray(Type $needleType): Type
253+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
254254
{
255255
if (
256256
$needleType instanceof ConstantScalarType && $this->valueType instanceof ConstantScalarType
257-
&& $needleType->getValue() === $this->valueType->getValue()
257+
&& (
258+
$needleType->getValue() === $this->valueType->getValue()
259+
// @phpstan-ignore equal.notAllowed
260+
|| ($strict->no() && $needleType->getValue() == $this->valueType->getValue()) // phpcs:ignore
261+
)
258262
) {
259263
return new UnionType([
260264
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
@@ -881,22 +881,31 @@ public function reverseArray(TrinaryLogic $preserveKeys): Type
881881
return $builder->getArray();
882882
}
883883

884-
public function searchArray(Type $needleType): Type
884+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
885885
{
886886
$matches = [];
887887
$hasIdenticalValue = false;
888888

889889
foreach ($this->valueTypes as $index => $valueType) {
890-
$isNeedleSuperType = $valueType->isSuperTypeOf($needleType);
891-
if ($isNeedleSuperType->no()) {
892-
continue;
890+
if ($strict->yes()) {
891+
$isNeedleSuperType = $valueType->isSuperTypeOf($needleType);
892+
if ($isNeedleSuperType->no()) {
893+
continue;
894+
}
893895
}
894896

895-
if ($needleType instanceof ConstantScalarType && $valueType instanceof ConstantScalarType
896-
&& $needleType->getValue() === $valueType->getValue()
897-
&& !$this->isOptionalKey($index)
898-
) {
899-
$hasIdenticalValue = true;
897+
if ($needleType instanceof ConstantScalarType && $valueType instanceof ConstantScalarType) {
898+
// @phpstan-ignore equal.notAllowed
899+
$isLooseEqual = $needleType->getValue() == $valueType->getValue(); // phpcs:ignore
900+
if (!$isLooseEqual) {
901+
continue;
902+
}
903+
if (
904+
($strict->no() || $needleType->getValue() === $valueType->getValue())
905+
&& !$this->isOptionalKey($index)
906+
) {
907+
$hasIdenticalValue = true;
908+
}
900909
}
901910

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

src/Type/IntersectionType.php

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

890-
public function searchArray(Type $needleType): Type
890+
public function searchArray(Type $needleType, TrinaryLogic $strict): Type
891891
{
892-
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType));
892+
return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType, $strict));
893893
}
894894

895895
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)