Skip to content

Commit

Permalink
Calling static:: preserves generic types
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Mar 12, 2021
1 parent 6d2cc5d commit d4e0177
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 47 deletions.
6 changes: 3 additions & 3 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,7 @@ private function resolveType(Expr $node): Type
return new ErrorType();
}

return new StaticType($this->getClassReflection()->getName());
return new StaticType($this->getClassReflection());
}
if ($lowercasedClassName === 'parent') {
return new NonexistentParentClassType();
Expand Down Expand Up @@ -1760,7 +1760,7 @@ private function resolveType(Expr $node): Type
$namesToResolve[] = 'static';
} elseif (strtolower($constantClass) === 'static') {
if (strtolower($constantName) === 'class') {
return new GenericClassStringType(new StaticType($this->getClassReflection()->getName()));
return new GenericClassStringType(new StaticType($this->getClassReflection()));
}
return new MixedType();
}
Expand Down Expand Up @@ -2452,7 +2452,7 @@ public function resolveTypeByName(Name $name): TypeWithClassName
if ($name->toLowerString() === 'static' && $this->isInClass()) {
$classReflection = $this->getClassReflection();

return new StaticType($classReflection->getName());
return new StaticType($classReflection);
}
$originalClass = $this->resolveName($name);
if ($this->isInClass()) {
Expand Down
2 changes: 1 addition & 1 deletion src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public function specifyTypesInCondition(
if ($lowercasedClassName === 'self' && $scope->isInClass()) {
$type = new ObjectType($scope->getClassReflection()->getName());
} elseif ($lowercasedClassName === 'static' && $scope->isInClass()) {
$type = new StaticType($scope->getClassReflection()->getName());
$type = new StaticType($scope->getClassReflection());
} elseif ($lowercasedClassName === 'parent') {
if (
$scope->isInClass()
Expand Down
32 changes: 27 additions & 5 deletions src/Type/StaticType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace PHPStan\Type;

use PHPStan\Broker\Broker;
use PHPStan\Reflection\ClassMemberAccessAnswerer;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ConstantReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateTypeHelper;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;

Expand All @@ -17,13 +20,22 @@ class StaticType implements TypeWithClassName
use NonGenericTypeTrait;
use UndecidedComparisonTypeTrait;

private string $baseClass;
private ClassReflection $classReflection;

private ?\PHPStan\Type\ObjectType $staticObjectType = null;

public function __construct(string $baseClass)
private string $baseClass;

/**
* @param string|ClassReflection $classReflection
*/
public function __construct($classReflection)
{
$this->baseClass = $baseClass;
if (is_string($classReflection)) {
$classReflection = Broker::getInstance()->getClass($classReflection);
}
$this->classReflection = $classReflection;
$this->baseClass = $classReflection->getName();
}

public function getClassName(): string
Expand All @@ -39,7 +51,17 @@ public function getAncestorWithClassName(string $className): ?ObjectType
public function getStaticObjectType(): ObjectType
{
if ($this->staticObjectType === null) {
$this->staticObjectType = new ObjectType($this->baseClass);
if ($this->classReflection->isGeneric()) {
$typeMap = $this->classReflection->getTemplateTypeMap()->map(static function (string $name, Type $type): Type {
return TemplateTypeHelper::toArgument($type);
});
return $this->staticObjectType = new GenericObjectType(
$this->classReflection->getName(),
$this->classReflection->typeMapToList($typeMap)
);
}

return $this->staticObjectType = new ObjectType($this->classReflection->getName(), null, $this->classReflection);
}

return $this->staticObjectType;
Expand Down Expand Up @@ -155,7 +177,7 @@ public function getConstant(string $constantName): ConstantReflection

public function changeBaseClass(ClassReflection $classReflection): self
{
return new self($classReflection->getName());
return new self($classReflection);
}

public function isIterable(): TrinaryLogic
Expand Down
38 changes: 0 additions & 38 deletions src/Type/ThisType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,11 @@

namespace PHPStan\Type;

use PHPStan\Broker\Broker;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateTypeHelper;

class ThisType extends StaticType
{

private ClassReflection $classReflection;

private ?\PHPStan\Type\ObjectType $staticObjectType = null;

/**
* @param string|ClassReflection $classReflection
*/
public function __construct($classReflection)
{
if (is_string($classReflection)) {
$classReflection = Broker::getInstance()->getClass($classReflection);
}
parent::__construct($classReflection->getName());
$this->classReflection = $classReflection;
}

public function getStaticObjectType(): ObjectType
{
if ($this->staticObjectType === null) {
if ($this->classReflection->isGeneric()) {
$typeMap = $this->classReflection->getTemplateTypeMap()->map(static function (string $name, Type $type): Type {
return TemplateTypeHelper::toArgument($type);
});
return $this->staticObjectType = new GenericObjectType(
$this->classReflection->getName(),
$this->classReflection->typeMapToList($typeMap)
);
}

return $this->staticObjectType = new ObjectType($this->classReflection->getName(), null, $this->classReflection);
}

return $this->staticObjectType;
}

public function changeBaseClass(ClassReflection $classReflection): StaticType
{
return new self($classReflection);
Expand Down
17 changes: 17 additions & 0 deletions tests/PHPStan/Analyser/data/generic-parent.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,20 @@ public function doFoo()
}

}

class E {}

/**
* @template T of E
*/
class R {

/** @return T */
function ret() { return $this->e; } // nonsense, to silence missing return

function test(): void {
assertType('T of GenericParent\E (class GenericParent\R, argument)', self::ret());
assertType('T of GenericParent\E (class GenericParent\R, argument)', $this->ret());
assertType('T of GenericParent\E (class GenericParent\R, argument)', static::ret());
}
}

0 comments on commit d4e0177

Please sign in to comment.