Skip to content

Commit 80b5cdd

Browse files
committed
IntersectionType - check if it's an oversized array and return benevolent union in getOffsetValueType
1 parent 40bc1f0 commit 80b5cdd

File tree

4 files changed

+33
-3
lines changed

4 files changed

+33
-3
lines changed

src/Type/BenevolentUnionType.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ protected function unionTypes(callable $getType): Type
4343
return TypeUtils::toBenevolentUnion(TypeCombinator::union(...$resultTypes));
4444
}
4545

46+
public function getOffsetValueType(Type $offsetType): Type
47+
{
48+
$types = [];
49+
foreach ($this->getTypes() as $innerType) {
50+
$valueType = $innerType->getOffsetValueType($offsetType);
51+
if ($valueType instanceof ErrorType) {
52+
continue;
53+
}
54+
55+
$types[] = $valueType;
56+
}
57+
58+
if (count($types) === 0) {
59+
return new ErrorType();
60+
}
61+
62+
return TypeUtils::toBenevolentUnion(TypeCombinator::union(...$types));
63+
}
64+
4665
protected function unionResults(callable $getResult): TrinaryLogic
4766
{
4867
return TrinaryLogic::createNo()->lazyOr($this->getTypes(), $getResult);

src/Type/IntersectionType.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,12 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic
576576

577577
public function getOffsetValueType(Type $offsetType): Type
578578
{
579-
return $this->intersectTypes(static fn (Type $type): Type => $type->getOffsetValueType($offsetType));
579+
$result = $this->intersectTypes(static fn (Type $type): Type => $type->getOffsetValueType($offsetType));
580+
if ($this->isOversizedArray()->yes()) {
581+
return TypeUtils::toBenevolentUnion($result);
582+
}
583+
584+
return $result;
580585
}
581586

582587
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type

src/Type/TypeCombinator.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,13 @@ private static function optimizeConstantArrays(array $types): array
676676
$keyTypes[$generalizedKeyType->describe(VerbosityLevel::precise())] = $generalizedKeyType;
677677

678678
$innerValueType = $type->getValueTypes()[$i];
679-
$generalizedValueType = $traverse($innerValueType);
679+
$generalizedValueType = TypeTraverser::map($innerValueType, static function (Type $type, callable $innerTraverse) use ($traverse): Type {
680+
if ($type instanceof ArrayType) {
681+
return TypeCombinator::intersect($type, new OversizedArrayType());
682+
}
683+
684+
return $traverse($type);
685+
});
680686
$valueTypes[$generalizedValueType->describe(VerbosityLevel::precise())] = $generalizedValueType;
681687
}
682688

tests/PHPStan/Analyser/data/bug-8004.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function getErrorsOnInvalidQuestions(array $importQuiz, int $key): array
7373
}
7474
}
7575

76-
assertType("list<array{line: int, type: 'empty_answer'|'empty_question'|'invalid_answer_1_too_long'|'invalid_answer_1_type'|'invalid_answer_2_too_long'|'invalid_answer_2_type'|'invalid_answer_3_too_long'|'invalid_answer_3_type'|'invalid_answer_4_too_long'|'invalid_answer_4_type'|'invalid_question_too_long'|'invalid_right_answer', value: int}>&oversized-array", $errors);
76+
assertType("list<array{line: int, type: 'empty_answer'|'empty_question'|'invalid_answer_1_too_long'|'invalid_answer_1_type'|'invalid_answer_2_too_long'|'invalid_answer_2_type'|'invalid_answer_3_too_long'|'invalid_answer_3_type'|'invalid_answer_4_too_long'|'invalid_answer_4_type'|'invalid_question_too_long'|'invalid_right_answer', value: int}&oversized-array>&oversized-array", $errors);
7777

7878
return $errors;
7979
}

0 commit comments

Comments
 (0)