Skip to content

Commit 65797b9

Browse files
Correctly consider impossible list
1 parent 8c56fba commit 65797b9

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -748,8 +748,12 @@ public function unsetOffset(Type $offsetType, bool $preserveListCertainty = fals
748748
$newOptionalKeys,
749749
$this->isList,
750750
in_array($i, $this->optionalKeys, true),
751-
$preserveListCertainty,
752751
);
752+
if (!$preserveListCertainty) {
753+
$newIsList = $newIsList->and(TrinaryLogic::createMaybe());
754+
} elseif ($this->isList->yes() && $newIsList->no()) {
755+
return new NeverType();
756+
}
753757

754758
return new self($newKeyTypes, $newValueTypes, $this->nextAutoIndexes, $newOptionalKeys, $newIsList);
755759
}
@@ -791,8 +795,12 @@ public function unsetOffset(Type $offsetType, bool $preserveListCertainty = fals
791795
$optionalKeys,
792796
$this->isList,
793797
count($optionalKeys) === count($this->optionalKeys),
794-
$preserveListCertainty,
795798
);
799+
if (!$preserveListCertainty) {
800+
$newIsList = $newIsList->and(TrinaryLogic::createMaybe());
801+
} elseif ($this->isList->yes() && $newIsList->no()) {
802+
return new NeverType();
803+
}
796804

797805
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, $optionalKeys, $newIsList);
798806
}
@@ -817,8 +825,12 @@ public function unsetOffset(Type $offsetType, bool $preserveListCertainty = fals
817825
$optionalKeys,
818826
$this->isList,
819827
count($optionalKeys) === count($this->optionalKeys),
820-
$preserveListCertainty,
821828
);
829+
if (!$preserveListCertainty) {
830+
$newIsList = $newIsList->and(TrinaryLogic::createMaybe());
831+
} elseif ($this->isList->yes() && $newIsList->no()) {
832+
return new NeverType();
833+
}
822834

823835
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, $optionalKeys, $newIsList);
824836
}
@@ -830,7 +842,7 @@ public function unsetOffset(Type $offsetType, bool $preserveListCertainty = fals
830842
* @param list<ConstantIntegerType|ConstantStringType> $newKeyTypes
831843
* @param int[] $newOptionalKeys
832844
*/
833-
private static function isListAfterUnset(array $newKeyTypes, array $newOptionalKeys, TrinaryLogic $arrayIsList, bool $unsetOptionalKey, bool $preserveListCertainty): TrinaryLogic
845+
private static function isListAfterUnset(array $newKeyTypes, array $newOptionalKeys, TrinaryLogic $arrayIsList, bool $unsetOptionalKey): TrinaryLogic
834846
{
835847
if (!$unsetOptionalKey || $arrayIsList->no()) {
836848
return TrinaryLogic::createNo();
@@ -854,7 +866,7 @@ private static function isListAfterUnset(array $newKeyTypes, array $newOptionalK
854866
}
855867
}
856868

857-
return $preserveListCertainty ? $arrayIsList : TrinaryLogic::createMaybe();
869+
return $arrayIsList;
858870
}
859871

860872
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type

tests/PHPStan/Analyser/nsrt/bug-14177.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,4 +200,25 @@ public function testUnsetInt(array $a, array $b, array $c, int $int): void
200200
assertType('bool', array_is_list($a));
201201
assertType('false', array_is_list($b));
202202
}
203+
204+
/**
205+
* @param list{0?: string, 1?: string, 2?: string} $l
206+
*/
207+
public function testFoo($l): void
208+
{
209+
if (array_key_exists(2, $l, true)) {
210+
assertType('true', array_is_list($l));
211+
assertType('list{0?: string, 1?: string, 2: string}', $l);
212+
if (array_key_exists(1, $l, true)) {
213+
assertType('true', array_is_list($l));
214+
assertType('list{0?: string, 1: string, 2: string}', $l);
215+
} else {
216+
assertType('true', array_is_list($l));
217+
assertType('*NEVER*', $l);
218+
}
219+
} else {
220+
assertType('true', array_is_list($l));
221+
assertType('list{0?: string, 1?: string}', $l);
222+
}
223+
}
203224
}

0 commit comments

Comments
 (0)