-
Notifications
You must be signed in to change notification settings - Fork 519
Fix get_class()
on HasMethodType
#2350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 1.10.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,13 +11,13 @@ | |
use PHPStan\Type\DynamicFunctionReturnTypeExtension; | ||
use PHPStan\Type\Enum\EnumCaseObjectType; | ||
use PHPStan\Type\Generic\GenericClassStringType; | ||
use PHPStan\Type\Generic\TemplateType; | ||
use PHPStan\Type\IntersectionType; | ||
use PHPStan\Type\MixedType; | ||
use PHPStan\Type\ObjectShapeType; | ||
use PHPStan\Type\ObjectType; | ||
use PHPStan\Type\ObjectWithoutClassType; | ||
use PHPStan\Type\StaticType; | ||
use PHPStan\Type\Type; | ||
use PHPStan\Type\TypeCombinator; | ||
use PHPStan\Type\TypeTraverser; | ||
use PHPStan\Type\TypeUtils; | ||
use PHPStan\Type\UnionType; | ||
|
@@ -64,27 +64,26 @@ static function (Type $type, callable $traverse): Type { | |
return new GenericClassStringType(new ObjectType($type->getClassName())); | ||
} | ||
|
||
$objectClassNames = $type->getObjectClassNames(); | ||
if ($type instanceof TemplateType && $objectClassNames === []) { | ||
if ($type instanceof ObjectWithoutClassType) { | ||
return new GenericClassStringType($type); | ||
$isObject = $type->isObject(); | ||
if ($isObject->yes() || $isObject->maybe()) { | ||
if ($type instanceof ObjectShapeType) { | ||
return new ClassStringType(); | ||
} | ||
|
||
$objectType = TypeCombinator::intersect($type, new ObjectWithoutClassType()); | ||
if ($objectType instanceof StaticType) { | ||
$objectType = $objectType->getStaticObjectType(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you checking this after an intersection? |
||
} | ||
$classStringType = new GenericClassStringType($objectType); | ||
|
||
if ($isObject->yes()) { | ||
return $classStringType; | ||
} | ||
|
||
return new UnionType([ | ||
new GenericClassStringType($type), | ||
new ConstantBooleanType(false), | ||
]); | ||
} elseif ($type instanceof MixedType) { | ||
return new UnionType([ | ||
new ClassStringType(), | ||
$classStringType, | ||
new ConstantBooleanType(false), | ||
]); | ||
} elseif ($type instanceof StaticType) { | ||
return new GenericClassStringType($type->getStaticObjectType()); | ||
} elseif ($objectClassNames !== []) { | ||
return new GenericClassStringType($type); | ||
} elseif ($type instanceof ObjectWithoutClassType) { | ||
return new ClassStringType(); | ||
} | ||
|
||
return new ConstantBooleanType(false); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
namespace Bug4890; | ||
|
||
use function PHPStan\Testing\assertType; | ||
|
||
interface Proxy {} | ||
|
||
class HelloWorld | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see https://phpstan.org/r/b6b95d5a-a3fb-4c29-be47-4e7832f00ddc regarding how this test fails before this PR |
||
{ | ||
public function update(object $entity): void | ||
{ | ||
assertType('class-string<object>', get_class($entity)); | ||
assert(method_exists($entity, 'getId')); | ||
assertType('class-string<object&hasMethod(getId)>', get_class($entity)); | ||
|
||
if ($entity instanceof Proxy) { | ||
assertType('class-string<Bug4890\Proxy&hasMethod(getId)>', get_class($entity)); | ||
} | ||
|
||
$class = $entity instanceof Proxy | ||
? get_parent_class($entity) | ||
: get_class($entity); | ||
assert(is_string($class)); | ||
|
||
} | ||
|
||
public function updateProp(object $entity): void | ||
{ | ||
assertType('class-string<object>', get_class($entity)); | ||
assert(property_exists($entity, 'myProp')); | ||
assertType('class-string<object&hasProperty(myProp)>', get_class($entity)); | ||
|
||
if ($entity instanceof Proxy) { | ||
assertType('class-string<Bug4890\Proxy&hasProperty(myProp)>', get_class($entity)); | ||
} | ||
|
||
$class = $entity instanceof Proxy | ||
? get_parent_class($entity) | ||
: get_class($entity); | ||
assert(is_string($class)); | ||
} | ||
|
||
/** | ||
* @param object{foo: self, bar: int, baz?: string} $entity | ||
*/ | ||
public function updateObjectShape($entity): void | ||
{ | ||
assertType('class-string', get_class($entity)); | ||
assert(property_exists($entity, 'foo')); | ||
assertType('class-string', get_class($entity)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace Bug4890b; | ||
|
||
interface Proxy {} | ||
|
||
class HelloWorld | ||
{ | ||
public function update(object $entity): void | ||
{ | ||
assert(method_exists($entity, 'getId')); | ||
|
||
$class = $entity instanceof Proxy | ||
? get_parent_class($entity) | ||
: get_class($entity); | ||
assert(is_string($class)); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For which type here it's going to be a
maybe
?