Skip to content

Commit

Permalink
Introduce Type::getTemplateType() and deprecate GenericTypeVariableRe…
Browse files Browse the repository at this point in the history
…solver
  • Loading branch information
ondrejmirtes committed Feb 2, 2023
1 parent 1409717 commit b73a8aa
Show file tree
Hide file tree
Showing 20 changed files with 139 additions and 72 deletions.
20 changes: 0 additions & 20 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ parameters:
count: 2
path: src/Analyser/MutatingScope.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) instead\\.$#"
count: 2
path: src/Analyser/MutatingScope.php

-
message: "#^Only numeric types are allowed in pre\\-decrement, bool\\|float\\|int\\|string\\|null given\\.$#"
count: 1
Expand Down Expand Up @@ -463,16 +458,6 @@ parameters:
count: 1
path: src/Rules/DirectRegistry.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) instead\\.$#"
count: 1
path: src/Rules/FunctionReturnTypeCheck.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) instead\\.$#"
count: 2
path: src/Rules/Generators/YieldFromTypeRule.php

-
message: "#^Function class_implements\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#"
count: 1
Expand Down Expand Up @@ -508,11 +493,6 @@ parameters:
count: 1
path: src/Rules/Methods/MethodParameterComparisonHelper.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) instead\\.$#"
count: 1
path: src/Rules/Missing/MissingReturnRule.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\NullType is error\\-prone and deprecated\\. Use Type\\:\\:isNull\\(\\) instead\\.$#"
count: 2
Expand Down
18 changes: 4 additions & 14 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeHelper;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\GenericTypeVariableResolver;
use PHPStan\Type\IntegerRangeType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
Expand Down Expand Up @@ -1426,25 +1425,16 @@ private function resolveType(string $exprString, Expr $node): Type
}

$returnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
if (!$returnType instanceof TypeWithClassName) {
return new MixedType();
}

$generatorSendType = GenericTypeVariableResolver::getType($returnType, Generator::class, 'TSend');
if ($generatorSendType === null) {
$generatorSendType = $returnType->getTemplateType(Generator::class, 'TSend');
if ($generatorSendType instanceof ErrorType) {
return new MixedType();
}

return $generatorSendType;
} elseif ($node instanceof Expr\YieldFrom) {
$yieldFromType = $this->getType($node->expr);

if (!$yieldFromType instanceof TypeWithClassName) {
return new MixedType();
}

$generatorReturnType = GenericTypeVariableResolver::getType($yieldFromType, Generator::class, 'TReturn');
if ($generatorReturnType === null) {
$generatorReturnType = $yieldFromType->getTemplateType(Generator::class, 'TReturn');
if ($generatorReturnType instanceof ErrorType) {
return new MixedType();
}

Expand Down
15 changes: 3 additions & 12 deletions src/Rules/FunctionReturnTypeCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
use PHPStan\Analyser\Scope;
use PHPStan\Type\GenericTypeVariableResolver;
use PHPStan\Type\ErrorType;
use PHPStan\Type\NeverType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\VerbosityLevel;
use PHPStan\Type\VoidType;
use function sprintf;
Expand Down Expand Up @@ -48,16 +47,8 @@ public function checkReturnType(
}

if ($isGenerator) {
if (!$returnType instanceof TypeWithClassName) {
return [];
}

$returnType = GenericTypeVariableResolver::getType(
$returnType,
Generator::class,
'TReturn',
);
if ($returnType === null) {
$returnType = $returnType->getTemplateType(Generator::class, 'TReturn');
if ($returnType instanceof ErrorType) {
return [];
}
}
Expand Down
17 changes: 4 additions & 13 deletions src/Rules/Generators/YieldFromTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\GenericTypeVariableResolver;
use PHPStan\Type\ErrorType;
use PHPStan\Type\MixedType;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\VerbosityLevel;
use function sprintf;

Expand Down Expand Up @@ -99,18 +98,10 @@ public function processNode(Node $node, Scope $scope): array
return $messages;
}

if (!$exprType instanceof TypeWithClassName) {
return $messages;
}

$currentReturnType = ParametersAcceptorSelector::selectSingle($scopeFunction->getVariants())->getReturnType();
if (!$currentReturnType instanceof TypeWithClassName) {
return $messages;
}

$exprSendType = GenericTypeVariableResolver::getType($exprType, Generator::class, 'TSend');
$thisSendType = GenericTypeVariableResolver::getType($currentReturnType, Generator::class, 'TSend');
if ($exprSendType === null || $thisSendType === null) {
$exprSendType = $exprType->getTemplateType(Generator::class, 'TSend');
$thisSendType = $currentReturnType->getTemplateType(Generator::class, 'TSend');
if ($exprSendType instanceof ErrorType || $thisSendType instanceof ErrorType) {
return $messages;
}

Expand Down
13 changes: 4 additions & 9 deletions src/Rules/Missing/MissingReturnRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Generic\TemplateMixedType;
use PHPStan\Type\GenericTypeVariableResolver;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\VerbosityLevel;
use PHPStan\Type\VoidType;
use function sprintf;
Expand Down Expand Up @@ -74,13 +73,9 @@ public function processNode(Node $node, Scope $scope): array
}

if ($statementResult->hasYield()) {
if ($returnType instanceof TypeWithClassName && $this->checkPhpDocMissingReturn) {
$generatorReturnType = GenericTypeVariableResolver::getType(
$returnType,
Generator::class,
'TReturn',
);
if ($generatorReturnType !== null) {
if ($this->checkPhpDocMissingReturn) {
$generatorReturnType = $returnType->getTemplateType(Generator::class, 'TReturn');
if (!$generatorReturnType instanceof ErrorType) {
$returnType = $generatorReturnType;
if ($returnType->isVoid()->yes()) {
return [];
Expand Down
5 changes: 5 additions & 0 deletions src/Type/ClosureType.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ public function isObject(): TrinaryLogic
return $this->objectType->isObject();
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return $this->objectType->getTemplateType($ancestorClassName, $templateTypeName);
}

public function canAccessProperties(): TrinaryLogic
{
return $this->objectType->canAccessProperties();
Expand Down
3 changes: 3 additions & 0 deletions src/Type/GenericTypeVariableResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
class GenericTypeVariableResolver
{

/**
* @deprecated Use Type::getTemplateType() instead.
*/
public static function getType(
TypeWithClassName $type,
string $genericClassName,
Expand Down
5 changes: 5 additions & 0 deletions src/Type/IntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,11 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes)
return implode('&', $describedTypes);
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return $this->intersectTypes(static fn (Type $type): Type => $type->getTemplateType($ancestorClassName, $templateTypeName));
}

public function isObject(): TrinaryLogic
{
return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isObject());
Expand Down
5 changes: 5 additions & 0 deletions src/Type/MixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes):
return AcceptsResult::createYes();
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return new self();
}

public function isObject(): TrinaryLogic
{
if ($this->subtractedType !== null) {
Expand Down
5 changes: 5 additions & 0 deletions src/Type/NeverType.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ public function describe(VerbosityLevel $level): string
return '*NEVER*';
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return new NeverType();
}

public function isObject(): TrinaryLogic
{
return TrinaryLogic::createNo();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/NonexistentParentClassType.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public function describe(VerbosityLevel $level): string
return 'parent';
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return new ErrorType();
}

public function isObject(): TrinaryLogic
{
return TrinaryLogic::createYes();
Expand Down
44 changes: 40 additions & 4 deletions src/Type/ObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\Enum\EnumCaseObjectType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateTypeHelper;
use PHPStan\Type\Traits\MaybeIterableTypeTrait;
use PHPStan\Type\Traits\NonArrayTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
Expand Down Expand Up @@ -769,6 +770,41 @@ public function getConstant(string $constantName): ConstantReflection
return $class->getConstant($constantName);
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
$classReflection = $this->getClassReflection();
if ($classReflection === null) {
return new ErrorType();
}

$ancestorClassReflection = $classReflection->getAncestorWithClassName($ancestorClassName);
if ($ancestorClassReflection === null) {
return new ErrorType();
}

$activeTemplateTypeMap = $ancestorClassReflection->getPossiblyIncompleteActiveTemplateTypeMap();
$type = $activeTemplateTypeMap->getType($templateTypeName);
if ($type === null) {
return new ErrorType();
}
if ($type instanceof ErrorType) {
$templateTypeMap = $ancestorClassReflection->getTemplateTypeMap();
$templateType = $templateTypeMap->getType($templateTypeName);
if ($templateType === null) {
return $type;
}

$bound = TemplateTypeHelper::resolveToBounds($templateType);
if ($bound instanceof MixedType && $bound->isExplicitMixed()) {
return new MixedType(false);
}

return $bound;
}

return $type;
}

public function getConstantStrings(): array
{
return [];
Expand Down Expand Up @@ -810,8 +846,8 @@ public function getIterableKeyType(): Type
$extraOffsetAccessible = $this->isExtraOffsetAccessibleClass()->yes();
if ($this->isInstanceOf(Traversable::class)->yes() && !$extraOffsetAccessible) {
$isTraversable = true;
$tKey = GenericTypeVariableResolver::getType($this, Traversable::class, 'TKey');
if ($tKey !== null) {
$tKey = $this->getTemplateType(Traversable::class, 'TKey');
if (!$tKey instanceof ErrorType) {
if (!$tKey instanceof MixedType || $tKey->isExplicitMixed()) {
return $tKey;
}
Expand Down Expand Up @@ -861,8 +897,8 @@ public function getIterableValueType(): Type
$extraOffsetAccessible = $this->isExtraOffsetAccessibleClass()->yes();
if ($this->isInstanceOf(Traversable::class)->yes() && !$extraOffsetAccessible) {
$isTraversable = true;
$tValue = GenericTypeVariableResolver::getType($this, Traversable::class, 'TValue');
if ($tValue !== null) {
$tValue = $this->getTemplateType(Traversable::class, 'TValue');
if (!$tValue instanceof ErrorType) {
if (!$tValue instanceof MixedType || $tValue->isExplicitMixed()) {
return $tValue;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Type/StaticType.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ public function describe(VerbosityLevel $level): string
return sprintf('static(%s)', $this->getStaticObjectType()->describe($level));
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return $this->getStaticObjectType()->getTemplateType($ancestorClassName, $templateTypeName);
}

public function isObject(): TrinaryLogic
{
return $this->getStaticObjectType()->isObject();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/StrictMixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public function describe(VerbosityLevel $level): string
return 'mixed';
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return new ErrorType();
}

public function isObject(): TrinaryLogic
{
return TrinaryLogic::createNo();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Traits/LateResolvableTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ private function isSuperTypeOfDefault(Type $type): TrinaryLogic
return $isSuperType;
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return $this->resolve()->getTemplateType($ancestorClassName, $templateTypeName);
}

public function isObject(): TrinaryLogic
{
return $this->resolve()->isObject();
Expand Down
6 changes: 6 additions & 0 deletions src/Type/Traits/MaybeObjectTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@
use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection;
use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;

trait MaybeObjectTypeTrait
{

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return new MixedType();
}

public function isObject(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
Expand Down
7 changes: 7 additions & 0 deletions src/Type/Traits/NonObjectTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;

trait NonObjectTypeTrait
{
Expand Down Expand Up @@ -89,4 +91,9 @@ public function getEnumCases(): array
return [];
}

public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
{
return new ErrorType();
}

}
Loading

0 comments on commit b73a8aa

Please sign in to comment.