Skip to content

Commit 5a1048a

Browse files
committed
Merge branch 2.1.x into 2.2.x
2 parents 991fb88 + 14bf97d commit 5a1048a

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

src/Type/TypeCombinator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ public static function intersect(Type ...$types): Type
12121212
for ($i = 0; $i < $typesCount; $i++) {
12131213
$type = $types[$i];
12141214

1215-
if ($type instanceof IntersectionType) {
1215+
if ($type instanceof IntersectionType && !$type instanceof TemplateType) {
12161216
// transform A & (B & C) to A & B & C
12171217
array_splice($types, $i--, 1, $type->getTypes());
12181218
$typesCount = count($types);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug13577;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class A {}
8+
interface B {}
9+
10+
/**
11+
* @template T of A&B
12+
*/
13+
class Foo
14+
{
15+
/**
16+
* @param T $foo
17+
*/
18+
public function a($foo): void
19+
{
20+
assertType('T of Bug13577\A&Bug13577\B (class Bug13577\Foo, argument)', $foo);
21+
22+
if (!$foo instanceof B) {
23+
throw new \Exception();
24+
}
25+
26+
assertType('T of Bug13577\A&Bug13577\B (class Bug13577\Foo, argument)', $foo);
27+
28+
$this->b($foo);
29+
}
30+
31+
/**
32+
* @param T $foo
33+
*/
34+
public function b($foo): void {}
35+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug14348;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
interface PositionEntityInterface {
8+
public function getPosition(): int;
9+
}
10+
interface TgEntityInterface {}
11+
12+
abstract class HelloWorld
13+
{
14+
/**
15+
* @phpstan-template T of PositionEntityInterface&TgEntityInterface
16+
*
17+
* @param non-empty-array<T> $tgs
18+
*/
19+
public function computeForFrontByPosition(array $tgs): void
20+
{
21+
assertType('T of Bug14348\PositionEntityInterface&Bug14348\TgEntityInterface (method Bug14348\HelloWorld::computeForFrontByPosition(), argument)', $tgs[0]);
22+
}
23+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug9961;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
interface Ia {}
8+
interface Ib {}
9+
interface Ic {}
10+
interface Id {}
11+
12+
class A implements Ia, Ib {}
13+
14+
class HelloWorld
15+
{
16+
/**
17+
* @template T of (Ia&Ib)|(Ic&Id)
18+
* @param T $a
19+
* @return T
20+
*/
21+
public function sayHello(Ia|Ic $a): mixed
22+
{
23+
if ($a instanceof Ic && $a instanceof Id) {
24+
assertType('T of Bug9961\Ic&Bug9961\Id (method Bug9961\HelloWorld::sayHello(), argument)', $a);
25+
} elseif ($a instanceof A) {
26+
assertType('Bug9961\A&T of T of Bug9961\Ia&Bug9961\Ib (method Bug9961\HelloWorld::sayHello(), argument) (method Bug9961\HelloWorld::sayHello(), argument)', $a);
27+
} else {
28+
throw new \Exception;
29+
}
30+
31+
assertType('(Bug9961\A&T of T of Bug9961\Ia&Bug9961\Ib (method Bug9961\HelloWorld::sayHello(), argument) (method Bug9961\HelloWorld::sayHello(), argument))|T of Bug9961\Ic&Bug9961\Id (method Bug9961\HelloWorld::sayHello(), argument)', $a);
32+
33+
return $a;
34+
}
35+
}

tests/PHPStan/Type/TypeCombinatorTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
use PHPStan\Type\Generic\GenericObjectType;
4343
use PHPStan\Type\Generic\GenericStaticType;
4444
use PHPStan\Type\Generic\TemplateBenevolentUnionType;
45+
use PHPStan\Type\Generic\TemplateIntersectionType;
4546
use PHPStan\Type\Generic\TemplateMixedType;
4647
use PHPStan\Type\Generic\TemplateObjectType;
4748
use PHPStan\Type\Generic\TemplateObjectWithoutClassType;
@@ -4917,6 +4918,21 @@ public static function dataIntersect(): iterable
49174918
ObjectType::class,
49184919
$nonFinalClass->getDisplayName() . '=final',
49194920
];
4921+
4922+
// https://github.com/phpstan/phpstan/issues/14348
4923+
yield [
4924+
[
4925+
TemplateTypeFactory::create(
4926+
TemplateTypeScope::createWithFunction('a'),
4927+
'T',
4928+
new IntersectionType([new ObjectType('Iterator'), new ObjectType('Countable')]),
4929+
TemplateTypeVariance::createInvariant(),
4930+
),
4931+
new MixedType(),
4932+
],
4933+
TemplateIntersectionType::class,
4934+
'T of Countable&Iterator (function a(), parameter)',
4935+
];
49204936
}
49214937

49224938
/**

0 commit comments

Comments
 (0)