Skip to content

Commit

Permalink
Deduplicate inferred template type generalization logic
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 13, 2023
1 parent a532baf commit 39fe102
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 21 deletions.
11 changes: 1 addition & 10 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -5063,16 +5063,7 @@ private function exactInstantiation(New_ $node, string $className): ?Type
return $type->getBound();
}

if (!$type->getVariance()->covariant()) {
$isArrayKey = $type->getBound()->describe(VerbosityLevel::precise()) === '(int|string)';
if ($newType->isScalar()->yes() && $isArrayKey) {
$newType = $newType->generalize(GeneralizePrecision::templateArgument());
} elseif ($newType->isConstantValue()->yes() && (!$type->getBound()->isScalar()->yes() || $isArrayKey)) {
$newType = $newType->generalize(GeneralizePrecision::templateArgument());
}
}

return $newType;
return TemplateTypeHelper::generalizeInferredTemplateType($type, $newType);
}

return $traverse($type);
Expand Down
12 changes: 1 addition & 11 deletions src/Reflection/ResolvedFunctionVariant.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use PHPStan\Reflection\Php\DummyParameterWithPhpDocs;
use PHPStan\Type\ConditionalTypeForParameter;
use PHPStan\Type\ErrorType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeHelper;
Expand All @@ -17,7 +16,6 @@
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\VerbosityLevel;
use function array_key_exists;
use function array_map;

Expand Down Expand Up @@ -184,15 +182,7 @@ private function resolveResolvableTemplateTypes(Type $type, TemplateTypeVariance
return $traverse($type);
}

if (!$type->getVariance()->covariant()) {
$isArrayKey = $type->getBound()->describe(VerbosityLevel::precise()) === '(int|string)';
if ($newType->isScalar()->yes() && $isArrayKey) {
$newType = $newType->generalize(GeneralizePrecision::templateArgument());
} elseif ($newType->isConstantValue()->yes() && (!$type->getBound()->isScalar()->yes() || $isArrayKey)) {
$newType = $newType->generalize(GeneralizePrecision::templateArgument());
}
}

$newType = TemplateTypeHelper::generalizeInferredTemplateType($type, $newType);
$variance = TemplateTypeVariance::createInvariant();
foreach ($references as $reference) {
// this uses identity to distinguish between different occurrences of the same template type
Expand Down
16 changes: 16 additions & 0 deletions src/Type/Generic/TemplateTypeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace PHPStan\Type\Generic;

use PHPStan\Type\ErrorType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\NonAcceptingNeverType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\VerbosityLevel;

class TemplateTypeHelper
{
Expand Down Expand Up @@ -93,4 +95,18 @@ public static function toArgument(Type $type): Type
});
}

public static function generalizeInferredTemplateType(TemplateType $templateType, Type $type): Type
{
if (!$templateType->getVariance()->covariant()) {
$isArrayKey = $templateType->getBound()->describe(VerbosityLevel::precise()) === '(int|string)';
if ($type->isScalar()->yes() && $isArrayKey) {
$type = $type->generalize(GeneralizePrecision::templateArgument());
} elseif ($type->isConstantValue()->yes() && (!$templateType->getBound()->isScalar()->yes() || $isArrayKey)) {
$type = $type->generalize(GeneralizePrecision::templateArgument());
}
}

return $type;
}

}

0 comments on commit 39fe102

Please sign in to comment.