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