Skip to content

Commit

Permalink
Simplify
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 18, 2022
1 parent 690a128 commit 761c269
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 73 deletions.
76 changes: 13 additions & 63 deletions src/Reflection/InitializerExprTypeResolver.php
Expand Up @@ -64,12 +64,11 @@
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;
use function array_keys;
use function array_shift;
use function array_values;
use function count;
use function dirname;
use function get_class;
use function in_array;
use function is_float;
use function is_int;
Expand Down Expand Up @@ -449,11 +448,7 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type
{
// degrade oversized constant arrays, supports only basic types. less precise but slim and fast.
if (count($expr->items) > ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) {
try {
return $this->builtDegradedConstantArray($expr, $getTypeCallback);
} catch (OversizedConstantArrayTypeException) {
// array contains items which we cannot infer the types for
}
return $this->buildDegradedConstantArray($expr, $getTypeCallback);
}

// more precise but less performant array resolving
Expand Down Expand Up @@ -516,86 +511,41 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type

/**
* @param callable(Expr): Type $getTypeCallback
*
* @throws OversizedConstantArrayTypeException
*/
private function builtDegradedConstantArray(Array_ $node, callable $getTypeCallback): Type
private function buildDegradedConstantArray(Array_ $node, callable $getTypeCallback): Type
{
$isList = true;
$isEmptyArray = true;
$isKeysNonEmptyString = true;
$isValuesNonEmptyString = true;

$valueTypes = [];
$itemKeyTypes = [];
$keyTypes = [];
foreach ($node->items as $item) {
if ($item === null) {
continue;
throw new ShouldNotHappenException();
}

$isEmptyArray = false;

$key = $item->key;
if ($key !== null) {
$isList = false;

$itemKeyType = $getTypeCallback($key);
if (!$itemKeyType instanceof ConstantScalarType || $key instanceof ClassConstFetch) {
throw new OversizedConstantArrayTypeException();
}
if (!$itemKeyType->isNonEmptyString()->yes()) {
$isKeysNonEmptyString = false;
}
$generalizedType = $itemKeyType->generalize(GeneralizePrecision::lessSpecific());
$itemKeyTypes[get_class($generalizedType)] = $generalizedType; // de-duplicate values
} else {
$isKeysNonEmptyString = false;
$generalizedKeyType = $itemKeyType->generalize(GeneralizePrecision::moreSpecific());
$keyTypes[$generalizedKeyType->describe(VerbosityLevel::precise())] = $generalizedKeyType;
}

$value = $item->value;
if ($value instanceof Array_) {
$valueTypes[] = $this->builtDegradedConstantArray($value, $getTypeCallback);
continue;
}

$itemValueType = $getTypeCallback($value);
if (!$itemValueType instanceof ConstantScalarType || $value instanceof ClassConstFetch) {
throw new OversizedConstantArrayTypeException();
}
if (!$itemValueType->isNonEmptyString()->yes()) {
$isValuesNonEmptyString = false;
}
$generalizedType = $itemValueType->generalize(GeneralizePrecision::lessSpecific());
$valueTypes[get_class($generalizedType)] = $generalizedType; // de-duplicate values
}

$keyType = new BenevolentUnionType([new IntegerType(), new StringType()]);
if (count($itemKeyTypes) === 1) {
$keyType = array_shift($itemKeyTypes);
}

if ($isKeysNonEmptyString) {
$keyType = TypeCombinator::intersect($keyType, new AccessoryNonEmptyStringType());
$generalizedValueType = $itemValueType->generalize(GeneralizePrecision::moreSpecific());
$valueTypes[$generalizedValueType->describe(VerbosityLevel::precise())] = $generalizedValueType;
}

$valueTypes = TypeCombinator::union(...array_values($valueTypes));
if ($isValuesNonEmptyString) {
$valueTypes = TypeCombinator::intersect($valueTypes, new AccessoryNonEmptyStringType());
}
$keyType = TypeCombinator::union(...array_values($keyTypes));
$valueType = TypeCombinator::union(...array_values($valueTypes));

$arrayType = new ArrayType($keyType, $valueTypes);
$arrayType = new ArrayType($keyType, $valueType);
if ($isList) {
$arrayType = AccessoryArrayListType::intersectWith($arrayType);
}

$types = [];
$types[] = $arrayType;
$types[] = new OversizedArrayType();
if (!$isEmptyArray) {
$types[] = new NonEmptyArrayType();
}

return TypeCombinator::intersect(...$types);
return TypeCombinator::intersect($arrayType, new NonEmptyArrayType(), new OversizedArrayType());
}

/**
Expand Down
10 changes: 0 additions & 10 deletions src/Reflection/OversizedConstantArrayTypeException.php

This file was deleted.

0 comments on commit 761c269

Please sign in to comment.