1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Helper;
4:
5: use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
6: use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode;
8: use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
9: use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
10: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
11: use PHPStan\Turbo\ShadowedByTurboExtension;
12: use PHPStan\Type\CompoundType;
13: use PHPStan\Type\Generic\TemplateTypeVariance;
14: use PHPStan\Type\LateResolvableType;
15: use PHPStan\Type\Traits\LateResolvableTypeTrait;
16: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
17: use PHPStan\Type\Type;
18: use PHPStan\Type\TypeUtils;
19: use PHPStan\Type\VerbosityLevel;
20: use function sprintf;
21:
22: /** @api */
23: #[ShadowedByTurboExtension(implementation: __DIR__ . '/../../../turbo-ext/src/GetTemplateTypeType.cpp')]
24: final class GetTemplateTypeType implements CompoundType, LateResolvableType
25: {
26:
27: use LateResolvableTypeTrait;
28: use NonGeneralizableTypeTrait;
29:
30: /**
31: * @param class-string $ancestorClassName
32: */
33: public function __construct(private Type $type, private string $ancestorClassName, private string $templateTypeName)
34: {
35: }
36:
37: public function getReferencedClasses(): array
38: {
39: return $this->type->getReferencedClasses();
40: }
41:
42: public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array
43: {
44: return $this->type->getReferencedTemplateTypes($positionVariance);
45: }
46:
47: public function equals(Type $type): bool
48: {
49: return $type instanceof self
50: && $this->type->equals($type->type);
51: }
52:
53: public function describe(VerbosityLevel $level): string
54: {
55: return sprintf('template-type<%s, %s, %s>', $this->type->describe($level), $this->ancestorClassName, $this->templateTypeName);
56: }
57:
58: public function isResolvable(): bool
59: {
60: return !TypeUtils::containsTemplateType($this->type);
61: }
62:
63: protected function getResult(): Type
64: {
65: return $this->type->getTemplateType($this->ancestorClassName, $this->templateTypeName);
66: }
67:
68: /**
69: * @param callable(Type): Type $cb
70: */
71: public function traverse(callable $cb): Type
72: {
73: $type = $cb($this->type);
74:
75: if ($this->type === $type) {
76: return $this;
77: }
78:
79: return new self($type, $this->ancestorClassName, $this->templateTypeName);
80: }
81:
82: public function traverseSimultaneously(Type $right, callable $cb): Type
83: {
84: if (!$right instanceof self) {
85: return $this;
86: }
87:
88: $type = $cb($this->type, $right->type);
89:
90: if ($this->type === $type) {
91: return $this;
92: }
93:
94: return new self($type, $this->ancestorClassName, $this->templateTypeName);
95: }
96:
97: public function toPhpDocNode(): TypeNode
98: {
99: return new GenericTypeNode(
100: new IdentifierTypeNode('template-type'),
101: [
102: $this->type->toPhpDocNode(),
103: new FullyQualifiedNameNode($this->ancestorClassName),
104: new ConstTypeNode(new ConstExprStringNode($this->templateTypeName, ConstExprStringNode::SINGLE_QUOTED)),
105: ],
106: );
107: }
108:
109: }
110: