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