Skip to content

Commit 0c15ab7

Browse files
committed
Merge branch 2.1.x into 2.2.x
2 parents a660652 + 758b6fe commit 0c15ab7

6 files changed

Lines changed: 187 additions & 0 deletions

File tree

src/Type/FileTypeMapper.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ final class FileTypeMapper
6666
/** @var array<string, true> */
6767
private array $inProcess = [];
6868

69+
/** @var array<string, NameScope> */
70+
private array $inProcessNameScopes = [];
71+
6972
/** @var array<string, ResolvedPhpDocBlock> */
7073
private array $resolvedPhpDocBlockCache = [];
7174

@@ -200,6 +203,9 @@ public function getNameScope(
200203
{
201204
$nameScopeKey = $this->getNameScopeKey($fileName, $className, $traitName, $functionName);
202205
if (isset($this->inProcess[$nameScopeKey])) {
206+
if (isset($this->inProcessNameScopes[$nameScopeKey])) {
207+
return $this->inProcessNameScopes[$nameScopeKey];
208+
}
203209
throw new NameScopeAlreadyBeingCreatedException();
204210
}
205211

@@ -288,6 +294,8 @@ public function getNameScope(
288294
continue;
289295
}
290296

297+
$this->inProcessNameScopes[$nameScopeKey] = $nameScope;
298+
291299
$templateTags = $this->phpDocNodeResolver->resolveTemplateTags($parent->getTemplatePhpDocNodes(), $nameScope);
292300
$templateTypeMap = new TemplateTypeMap(array_map(static fn (TemplateTag $tag): Type => TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag), $templateTags));
293301
$nameScope = $nameScope->withTemplateTypeMap($templateTypeMap, $templateTags);
@@ -319,6 +327,7 @@ public function getNameScope(
319327
);
320328
} finally {
321329
unset($this->inProcess[$nameScopeKey]);
330+
unset($this->inProcessNameScopes[$nameScopeKey]);
322331
}
323332
}
324333

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11314;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @phpstan-type Breed 'Siamese'|'British Shorthair'|'Maine Coon'
9+
*/
10+
class Cat
11+
{
12+
/**
13+
* @var Breed
14+
*/
15+
public string $breed;
16+
}
17+
18+
/**
19+
* @phpstan-import-type Breed from Cat
20+
*
21+
* @template T of Breed
22+
*/
23+
class Cat2
24+
{
25+
/**
26+
* @var Breed
27+
*/
28+
public string $breed;
29+
}
30+
31+
/**
32+
* @phpstan-import-type Breed from Cat
33+
*/
34+
class Cat3
35+
{
36+
/**
37+
* @var Breed
38+
*/
39+
public string $breed;
40+
}
41+
42+
function () {
43+
$cat = new Cat();
44+
assertType("'British Shorthair'|'Maine Coon'|'Siamese'", $cat->breed);
45+
46+
$cat2 = new Cat2();
47+
assertType("'British Shorthair'|'Maine Coon'|'Siamese'", $cat2->breed);
48+
49+
$cat3 = new Cat3();
50+
assertType("'British Shorthair'|'Maine Coon'|'Siamese'", $cat3->breed);
51+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php // lint >= 8.1
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug13332;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
enum TestEnum {
10+
case A;
11+
case B;
12+
}
13+
14+
/**
15+
* @phpstan-type KeyType string|int|\UnitEnum|object
16+
*
17+
* @template K of KeyType
18+
*/
19+
class TestError
20+
{
21+
/** @param K $key */
22+
public function __construct(private readonly mixed $key)
23+
{
24+
}
25+
26+
/** @return self<TestEnum> */
27+
public static function makeEnum(): self
28+
{
29+
return new self(TestEnum::A);
30+
}
31+
32+
/** @return self<string> */
33+
public static function makeString(): self
34+
{
35+
return new self('foo');
36+
}
37+
}
38+
39+
/**
40+
* @template K of string|int|\UnitEnum|object
41+
*/
42+
class TestOk
43+
{
44+
/** @param K $key */
45+
public function __construct(private readonly mixed $key)
46+
{
47+
}
48+
49+
/** @return self<TestEnum> */
50+
public static function makeEnum(): self
51+
{
52+
return new self(TestEnum::A);
53+
}
54+
}
55+
56+
function () {
57+
$error = TestError::makeEnum();
58+
assertType('Bug13332\TestError<Bug13332\TestEnum>', $error);
59+
60+
$errorStr = TestError::makeString();
61+
assertType('Bug13332\TestError<string>', $errorStr);
62+
63+
$ok = TestOk::makeEnum();
64+
assertType('Bug13332\TestOk<Bug13332\TestEnum>', $ok);
65+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug7152;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @template T of array<mixed>
9+
*/
10+
class Root
11+
{
12+
/** @var T */
13+
public array $value;
14+
}
15+
16+
/**
17+
* @phpstan-type Foo array<int>
18+
* @template T of Foo
19+
* @extends Root<T>
20+
*/
21+
class Middle extends Root
22+
{
23+
}
24+
25+
/**
26+
* @template T of array<int>
27+
* @extends Root<T>
28+
*/
29+
class Middle2 extends Root
30+
{
31+
}
32+
33+
function () {
34+
/** @var Middle<array<int>> $m */
35+
$m = new Middle();
36+
assertType('array<int>', $m->value);
37+
38+
/** @var Middle2<array<int>> $m2 */
39+
$m2 = new Middle2();
40+
assertType('array<int>', $m2->value);
41+
};

tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,9 @@ public function testBug7021(): void
290290
$this->analyse([__DIR__ . '/data/bug-7021.php'], []);
291291
}
292292

293+
public function testBug7152(): void
294+
{
295+
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-7152.php'], []);
296+
}
297+
293298
}

tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,20 @@ public function testBug10049(): void
151151
]);
152152
}
153153

154+
public function testBug11314(): void
155+
{
156+
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-11314.php'], []);
157+
}
158+
159+
#[RequiresPhp('>= 8.1.0')]
160+
public function testBug13332(): void
161+
{
162+
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-13332.php'], []);
163+
}
164+
165+
public function testBug7152(): void
166+
{
167+
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-7152.php'], []);
168+
}
169+
154170
}

0 commit comments

Comments
 (0)