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