Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/Type/FileTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ final class FileTypeMapper
/** @var array<string, true> */
private array $inProcess = [];

/** @var array<string, NameScope> */
private array $inProcessNameScopes = [];

/** @var array<string, ResolvedPhpDocBlock> */
private array $resolvedPhpDocBlockCache = [];

Expand Down Expand Up @@ -200,6 +203,9 @@ public function getNameScope(
{
$nameScopeKey = $this->getNameScopeKey($fileName, $className, $traitName, $functionName);
if (isset($this->inProcess[$nameScopeKey])) {
if (isset($this->inProcessNameScopes[$nameScopeKey])) {
return $this->inProcessNameScopes[$nameScopeKey];
}
throw new NameScopeAlreadyBeingCreatedException();
}

Expand Down Expand Up @@ -288,6 +294,8 @@ public function getNameScope(
continue;
}

$this->inProcessNameScopes[$nameScopeKey] = $nameScope;

$templateTags = $this->phpDocNodeResolver->resolveTemplateTags($parent->getTemplatePhpDocNodes(), $nameScope);
$templateTypeMap = new TemplateTypeMap(array_map(static fn (TemplateTag $tag): Type => TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag), $templateTags));
$nameScope = $nameScope->withTemplateTypeMap($templateTypeMap, $templateTags);
Expand Down Expand Up @@ -319,6 +327,7 @@ public function getNameScope(
);
} finally {
unset($this->inProcess[$nameScopeKey]);
unset($this->inProcessNameScopes[$nameScopeKey]);
}
}

Expand Down
51 changes: 51 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-11314.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php declare(strict_types = 1);
Comment thread
staabm marked this conversation as resolved.

namespace Bug11314;

use function PHPStan\Testing\assertType;

/**
* @phpstan-type Breed 'Siamese'|'British Shorthair'|'Maine Coon'
*/
class Cat
{
/**
* @var Breed
*/
public string $breed;
}

/**
* @phpstan-import-type Breed from Cat
*
* @template T of Breed
*/
class Cat2
{
/**
* @var Breed
*/
public string $breed;
}

/**
* @phpstan-import-type Breed from Cat
*/
class Cat3
{
/**
* @var Breed
*/
public string $breed;
}

function () {
$cat = new Cat();
assertType("'British Shorthair'|'Maine Coon'|'Siamese'", $cat->breed);

$cat2 = new Cat2();
assertType("'British Shorthair'|'Maine Coon'|'Siamese'", $cat2->breed);

$cat3 = new Cat3();
assertType("'British Shorthair'|'Maine Coon'|'Siamese'", $cat3->breed);
};
65 changes: 65 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-13332.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php // lint >= 8.1

declare(strict_types = 1);

namespace Bug13332;

use function PHPStan\Testing\assertType;

enum TestEnum {
case A;
case B;
}

/**
* @phpstan-type KeyType string|int|\UnitEnum|object
*
* @template K of KeyType
*/
class TestError
{
/** @param K $key */
public function __construct(private readonly mixed $key)
{
}

/** @return self<TestEnum> */
public static function makeEnum(): self
{
return new self(TestEnum::A);
}

/** @return self<string> */
public static function makeString(): self
{
return new self('foo');
}
}

/**
* @template K of string|int|\UnitEnum|object
*/
class TestOk
{
/** @param K $key */
public function __construct(private readonly mixed $key)
{
}

/** @return self<TestEnum> */
public static function makeEnum(): self
{
return new self(TestEnum::A);
}
}

function () {
$error = TestError::makeEnum();
assertType('Bug13332\TestError<Bug13332\TestEnum>', $error);

$errorStr = TestError::makeString();
assertType('Bug13332\TestError<string>', $errorStr);

$ok = TestOk::makeEnum();
assertType('Bug13332\TestOk<Bug13332\TestEnum>', $ok);
};
41 changes: 41 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-7152.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types = 1);

namespace Bug7152;

use function PHPStan\Testing\assertType;

/**
* @template T of array<mixed>
*/
class Root
{
/** @var T */
public array $value;
}

/**
* @phpstan-type Foo array<int>
* @template T of Foo
* @extends Root<T>
*/
class Middle extends Root
{
}

/**
* @template T of array<int>
* @extends Root<T>
*/
class Middle2 extends Root
{
}

function () {
/** @var Middle<array<int>> $m */
$m = new Middle();
assertType('array<int>', $m->value);

/** @var Middle2<array<int>> $m2 */
$m2 = new Middle2();
assertType('array<int>', $m2->value);
};
Loading