Skip to content

Commit 0d28835

Browse files
committed
Fixed intersecting and removal from TemplateUnionType
1 parent ccffbc3 commit 0d28835

File tree

7 files changed

+111
-6
lines changed

7 files changed

+111
-6
lines changed

src/Type/Generic/TemplateTypeTrait.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
use PHPStan\TrinaryLogic;
66
use PHPStan\Type\IntersectionType;
77
use PHPStan\Type\MixedType;
8-
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
98
use PHPStan\Type\Type;
9+
use PHPStan\Type\TypeCombinator;
1010
use PHPStan\Type\UnionType;
1111
use PHPStan\Type\VerbosityLevel;
1212
use function sprintf;
@@ -17,8 +17,6 @@
1717
trait TemplateTypeTrait
1818
{
1919

20-
use NonRemoveableTypeTrait;
21-
2220
private string $name;
2321

2422
private TemplateTypeScope $scope;
@@ -198,6 +196,22 @@ protected function shouldGeneralizeInferredType(): bool
198196
return true;
199197
}
200198

199+
public function tryRemove(Type $typeToRemove): ?Type
200+
{
201+
$removedBound = TypeCombinator::remove($this->getBound(), $typeToRemove);
202+
$type = TemplateTypeFactory::create(
203+
$this->getScope(),
204+
$this->getName(),
205+
$removedBound,
206+
$this->getVariance(),
207+
);
208+
if ($this->isArgument()) {
209+
return TemplateTypeHelper::toArgument($type);
210+
}
211+
212+
return $type;
213+
}
214+
201215
/**
202216
* @param mixed[] $properties
203217
*/

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ public function dataFileAsserts(): iterable
694694
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Comparison/data/bug-6473.php');
695695
}
696696
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6500.php');
697+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6566-types.php');
697698
}
698699

699700
/**
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Bug6566Types;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class A {
8+
public string $name;
9+
}
10+
11+
class B {
12+
public string $name;
13+
}
14+
15+
class C {
16+
17+
}
18+
19+
/**
20+
* @template T of A|B|C
21+
*/
22+
abstract class HelloWorld
23+
{
24+
public function sayHelloBug(): void
25+
{
26+
$object = $this->getObject();
27+
assertType('T of Bug6566Types\A|Bug6566Types\B|Bug6566Types\C (class Bug6566Types\HelloWorld, argument)', $object);
28+
if ($object instanceof C) {
29+
assertType('T of Bug6566Types\C (class Bug6566Types\HelloWorld, argument)', $object);
30+
return;
31+
}
32+
assertType('T of Bug6566Types\A|Bug6566Types\B (class Bug6566Types\HelloWorld, argument)', $object);
33+
if ($object instanceof B) {
34+
assertType('T of Bug6566Types\B (class Bug6566Types\HelloWorld, argument)', $object);
35+
return;
36+
}
37+
assertType('T of Bug6566Types\A (class Bug6566Types\HelloWorld, argument)', $object);
38+
if ($object instanceof A) {
39+
assertType('T of Bug6566Types\A (class Bug6566Types\HelloWorld, argument)', $object);
40+
return;
41+
}
42+
assertType('*NEVER*', $object);
43+
}
44+
45+
/**
46+
* @return T
47+
*/
48+
abstract protected function getObject(): A|B|C;
49+
}

tests/PHPStan/Analyser/data/generics.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ function testGenericObjectWithoutClassType2($a)
10891089
return $a;
10901090
}
10911091

1092-
assertType('T of object (function PHPStan\Generics\FunctionsAssertType\testGenericObjectWithoutClassType2(), argument)', $b);
1092+
assertType('T of object~stdClass (function PHPStan\Generics\FunctionsAssertType\testGenericObjectWithoutClassType2(), argument)', $b);
10931093

10941094
return $a;
10951095
}

tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,4 +543,11 @@ public function testBug6385(): void
543543
]);
544544
}
545545

546+
public function testBug6566(): void
547+
{
548+
$this->checkThisOnly = false;
549+
$this->checkUnionTypes = true;
550+
$this->analyse([__DIR__ . '/data/bug-6566.php'], []);
551+
}
552+
546553
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Bug6566;
4+
5+
class A {
6+
public string $name;
7+
}
8+
9+
class B {
10+
public string $name;
11+
}
12+
13+
class C {
14+
15+
}
16+
17+
/**
18+
* @template T of A|B|C
19+
*/
20+
abstract class HelloWorld
21+
{
22+
public function sayHelloBug(): void
23+
{
24+
$object = $this->getObject();
25+
if (!$object instanceof C) {
26+
echo $object->name;
27+
}
28+
}
29+
30+
/**
31+
* @return T
32+
*/
33+
abstract protected function getObject(): A|B|C;
34+
}

tests/PHPStan/Type/TypeCombinatorTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3914,8 +3914,8 @@ public function dataRemove(): array
39143914
TemplateTypeVariance::createInvariant(),
39153915
),
39163916
new ConstantBooleanType(false),
3917-
TemplateBooleanType::class,
3918-
'T of bool (class Foo, parameter)',
3917+
TemplateMixedType::class, // should be TemplateConstantBooleanType
3918+
'T (class Foo, parameter)', // should be T of true
39193919
],
39203920
];
39213921
}

0 commit comments

Comments
 (0)