1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
6: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7: use PHPStan\PhpDocParser\Printer\Printer;
8: use PHPStan\Type\Generic\TemplateTypeVariance;
9: use PHPStan\Type\Traits\LateResolvableTypeTrait;
10: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
11: use function array_merge;
12:
13: /** @api */
14: final class OffsetAccessType implements CompoundType, LateResolvableType
15: {
16:
17: use LateResolvableTypeTrait;
18: use NonGeneralizableTypeTrait;
19:
20: public function __construct(
21: private Type $type,
22: private Type $offset,
23: )
24: {
25: }
26:
27: public function getReferencedClasses(): array
28: {
29: return array_merge(
30: $this->type->getReferencedClasses(),
31: $this->offset->getReferencedClasses(),
32: );
33: }
34:
35: public function getObjectClassNames(): array
36: {
37: return [];
38: }
39:
40: public function getObjectClassReflections(): array
41: {
42: return [];
43: }
44:
45: public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array
46: {
47: return array_merge(
48: $this->type->getReferencedTemplateTypes($positionVariance),
49: $this->offset->getReferencedTemplateTypes($positionVariance),
50: );
51: }
52:
53: public function equals(Type $type): bool
54: {
55: return $type instanceof self
56: && $this->type->equals($type->type)
57: && $this->offset->equals($type->offset);
58: }
59:
60: public function describe(VerbosityLevel $level): string
61: {
62: $printer = new Printer();
63:
64: return $printer->print($this->toPhpDocNode());
65: }
66:
67: public function isResolvable(): bool
68: {
69: return !TypeUtils::containsTemplateType($this->type)
70: && !TypeUtils::containsTemplateType($this->offset);
71: }
72:
73: protected function getResult(): Type
74: {
75: return $this->type->getOffsetValueType($this->offset);
76: }
77:
78: /**
79: * @param callable(Type): Type $cb
80: */
81: public function traverse(callable $cb): Type
82: {
83: $type = $cb($this->type);
84: $offset = $cb($this->offset);
85:
86: if ($this->type === $type && $this->offset === $offset) {
87: return $this;
88: }
89:
90: return new self($type, $offset);
91: }
92:
93: public function traverseSimultaneously(Type $right, callable $cb): Type
94: {
95: if (!$right instanceof self) {
96: return $this;
97: }
98:
99: $type = $cb($this->type, $right->type);
100: $offset = $cb($this->offset, $right->offset);
101:
102: if ($this->type === $type && $this->offset === $offset) {
103: return $this;
104: }
105:
106: return new self($type, $offset);
107: }
108:
109: public function toPhpDocNode(): TypeNode
110: {
111: return new OffsetAccessTypeNode(
112: $this->type->toPhpDocNode(),
113: $this->offset->toPhpDocNode(),
114: );
115: }
116:
117: /**
118: * @param mixed[] $properties
119: */
120: public static function __set_state(array $properties): Type
121: {
122: return new self(
123: $properties['type'],
124: $properties['offset'],
125: );
126: }
127:
128: }
129: