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