Skip to content

Commit

Permalink
IntersectionType - check if it's an oversized array and return benevo…
Browse files Browse the repository at this point in the history
…lent union in getOffsetValueType
  • Loading branch information
ondrejmirtes committed Jan 2, 2023
1 parent 40bc1f0 commit 80b5cdd
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 3 deletions.
19 changes: 19 additions & 0 deletions src/Type/BenevolentUnionType.php
Expand Up @@ -43,6 +43,25 @@ protected function unionTypes(callable $getType): Type
return TypeUtils::toBenevolentUnion(TypeCombinator::union(...$resultTypes));
}

public function getOffsetValueType(Type $offsetType): Type
{
$types = [];
foreach ($this->getTypes() as $innerType) {
$valueType = $innerType->getOffsetValueType($offsetType);
if ($valueType instanceof ErrorType) {
continue;
}

$types[] = $valueType;
}

if (count($types) === 0) {
return new ErrorType();
}

return TypeUtils::toBenevolentUnion(TypeCombinator::union(...$types));
}

protected function unionResults(callable $getResult): TrinaryLogic
{
return TrinaryLogic::createNo()->lazyOr($this->getTypes(), $getResult);
Expand Down
7 changes: 6 additions & 1 deletion src/Type/IntersectionType.php
Expand Up @@ -576,7 +576,12 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic

public function getOffsetValueType(Type $offsetType): Type
{
return $this->intersectTypes(static fn (Type $type): Type => $type->getOffsetValueType($offsetType));
$result = $this->intersectTypes(static fn (Type $type): Type => $type->getOffsetValueType($offsetType));
if ($this->isOversizedArray()->yes()) {
return TypeUtils::toBenevolentUnion($result);
}

return $result;
}

public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
Expand Down
8 changes: 7 additions & 1 deletion src/Type/TypeCombinator.php
Expand Up @@ -676,7 +676,13 @@ private static function optimizeConstantArrays(array $types): array
$keyTypes[$generalizedKeyType->describe(VerbosityLevel::precise())] = $generalizedKeyType;

$innerValueType = $type->getValueTypes()[$i];
$generalizedValueType = $traverse($innerValueType);
$generalizedValueType = TypeTraverser::map($innerValueType, static function (Type $type, callable $innerTraverse) use ($traverse): Type {
if ($type instanceof ArrayType) {
return TypeCombinator::intersect($type, new OversizedArrayType());
}

return $traverse($type);
});
$valueTypes[$generalizedValueType->describe(VerbosityLevel::precise())] = $generalizedValueType;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/data/bug-8004.php
Expand Up @@ -73,7 +73,7 @@ public function getErrorsOnInvalidQuestions(array $importQuiz, int $key): array
}
}

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

return $errors;
}
Expand Down

0 comments on commit 80b5cdd

Please sign in to comment.