Skip to content

Commit

Permalink
Merge branch refs/heads/1.12.x into 2.1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
phpstan-bot authored Jan 5, 2025
2 parents 7c281ba + a063119 commit 82a6961
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 2 deletions.
66 changes: 65 additions & 1 deletion src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -5631,13 +5631,77 @@ private function exactInstantiation(New_ $node, string $className): ?Type
}
}

if ($constructorMethod instanceof DummyConstructorReflection || $constructorMethod->getDeclaringClass()->getName() !== $classReflection->getName()) {
if ($constructorMethod instanceof DummyConstructorReflection) {
return new GenericObjectType(
$resolvedClassName,
$classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds()),
);
}

if ($constructorMethod->getDeclaringClass()->getName() !== $classReflection->getName()) {
if (!$constructorMethod->getDeclaringClass()->isGeneric()) {
return new GenericObjectType(
$resolvedClassName,
$classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds()),
);
}
$newType = new GenericObjectType($resolvedClassName, $classReflection->typeMapToList($classReflection->getTemplateTypeMap()));
$ancestorType = $newType->getAncestorWithClassName($constructorMethod->getDeclaringClass()->getName());
if ($ancestorType === null) {
return new GenericObjectType(
$resolvedClassName,
$classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds()),
);
}
$ancestorClassReflections = $ancestorType->getObjectClassReflections();
if (count($ancestorClassReflections) !== 1) {
return new GenericObjectType(
$resolvedClassName,
$classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds()),
);
}

$newParentNode = new New_(new Name($constructorMethod->getDeclaringClass()->getName()), $node->args);
$newParentType = $this->getType($newParentNode);
$newParentTypeClassReflections = $newParentType->getObjectClassReflections();
if (count($newParentTypeClassReflections) !== 1) {
return new GenericObjectType(
$resolvedClassName,
$classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds()),
);
}
$newParentTypeClassReflection = $newParentTypeClassReflections[0];

$ancestorClassReflection = $ancestorClassReflections[0];
$ancestorMapping = [];
foreach ($ancestorClassReflection->getActiveTemplateTypeMap()->getTypes() as $typeName => $templateType) {
if (!$templateType instanceof TemplateType) {
continue;
}

$ancestorMapping[$typeName] = $templateType->getName();
}

$resolvedTypeMap = [];
foreach ($newParentTypeClassReflection->getActiveTemplateTypeMap()->getTypes() as $typeName => $type) {
if (!array_key_exists($typeName, $ancestorMapping)) {
continue;
}

if (!array_key_exists($ancestorMapping[$typeName], $resolvedTypeMap)) {
$resolvedTypeMap[$ancestorMapping[$typeName]] = $type;
continue;
}

$resolvedTypeMap[$ancestorMapping[$typeName]] = TypeCombinator::union($resolvedTypeMap[$ancestorMapping[$typeName]], $type);
}

return new GenericObjectType(
$resolvedClassName,
$classReflection->typeMapToList(new TemplateTypeMap($resolvedTypeMap)),
);
}

$parametersAcceptor = ParametersAcceptorSelector::selectFromArgs(
$this,
$methodCall->getArgs(),
Expand Down
134 changes: 134 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-2735.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

namespace Bug2735;

use function PHPStan\Testing\assertType;

class Dog {}

class Cat {}

/**
* @template T
*/
class Collection {
/** @var array<T> */
protected $arr = [];

/**
* @param array<T> $arr
*/
public function __construct(array $arr) {
$this->arr = $arr;
}

/**
* @return T
*/
public function last()
{
if (!$this->arr) {
throw new \Exception('bad');
}
return end($this->arr);
}
}

/**
* @template T
* @extends Collection<T>
*/
class CollectionChild extends Collection {
}

$dogs = new CollectionChild([new Dog(), new Dog()]);
assertType('Bug2735\\CollectionChild<Bug2735\\Dog>', $dogs);

/**
* @template X
* @template Y
*/
class ParentWithConstructor
{

/**
* @param X $x
* @param Y $y
*/
public function __construct($x, $y)
{
}

}

/**
* @template T
* @extends ParentWithConstructor<int, T>
*/
class ChildOne extends ParentWithConstructor
{

}

function (): void {
$a = new ChildOne(1, new Dog());
assertType('Bug2735\\ChildOne<Bug2735\\Dog>', $a);
};

/**
* @template T
* @extends ParentWithConstructor<T, int>
*/
class ChildTwo extends ParentWithConstructor
{

}

function (): void {
$a = new ChildTwo(new Cat(), 2);
assertType('Bug2735\\ChildTwo<Bug2735\\Cat>', $a);
};

/**
* @template T
* @extends ParentWithConstructor<T, T>
*/
class ChildThree extends ParentWithConstructor
{

}

function (): void {
$a = new ChildThree(new Cat(), new Dog());
assertType('Bug2735\\ChildThree<Bug2735\\Cat|Bug2735\\Dog>', $a);
};

/**
* @template T
* @template U
* @extends ParentWithConstructor<T, U>
*/
class ChildFour extends ParentWithConstructor
{

}

function (): void {
$a = new ChildFour(new Cat(), new Dog());
assertType('Bug2735\\ChildFour<Bug2735\\Cat, Bug2735\\Dog>', $a);
};

/**
* @template T
* @template U
* @extends ParentWithConstructor<U, T>
*/
class ChildFive extends ParentWithConstructor
{

}

function (): void {
$a = new ChildFive(new Cat(), new Dog());
assertType('Bug2735\\ChildFive<Bug2735\\Dog, Bug2735\\Cat>', $a);
};
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/generics.php
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ function testClasses()
assertType('DateTime', $ab->getB(new \DateTime()));

$noConstructor = new NoConstructor(1);
assertType('PHPStan\Generics\FunctionsAssertType\NoConstructor<mixed>', $noConstructor);
assertType('PHPStan\Generics\FunctionsAssertType\NoConstructor<int>', $noConstructor);

assertType('stdClass', acceptsClassString(\stdClass::class));
assertType('class-string<stdClass>', returnsClassString(new \stdClass()));
Expand Down

0 comments on commit 82a6961

Please sign in to comment.