1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\TrinaryLogic;
6: use PHPStan\Type\CompoundType;
7: use PHPStan\Type\Constant\ConstantArrayType;
8: use PHPStan\Type\Constant\ConstantIntegerType;
9: use PHPStan\Type\Constant\ConstantStringType;
10: use PHPStan\Type\ErrorType;
11: use PHPStan\Type\FloatType;
12: use PHPStan\Type\GeneralizePrecision;
13: use PHPStan\Type\IntegerType;
14: use PHPStan\Type\IntersectionType;
15: use PHPStan\Type\StringType;
16: use PHPStan\Type\Traits\MaybeCallableTypeTrait;
17: use PHPStan\Type\Traits\NonGenericTypeTrait;
18: use PHPStan\Type\Traits\NonIterableTypeTrait;
19: use PHPStan\Type\Traits\NonObjectTypeTrait;
20: use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
21: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
22: use PHPStan\Type\Type;
23: use PHPStan\Type\TypeCombinator;
24: use PHPStan\Type\UnionType;
25: use PHPStan\Type\VerbosityLevel;
26:
27: class AccessoryNonEmptyStringType implements CompoundType, AccessoryType
28: {
29:
30: use MaybeCallableTypeTrait;
31: use NonObjectTypeTrait;
32: use NonIterableTypeTrait;
33: use UndecidedComparisonCompoundTypeTrait;
34: use NonGenericTypeTrait;
35: use UndecidedBooleanTypeTrait;
36:
37: /** @api */
38: public function __construct()
39: {
40: }
41:
42: public function getReferencedClasses(): array
43: {
44: return [];
45: }
46:
47: public function accepts(Type $type, bool $strictTypes): TrinaryLogic
48: {
49: if ($type instanceof CompoundType) {
50: return $type->isAcceptedBy($this, $strictTypes);
51: }
52:
53: return $type->isNonEmptyString();
54: }
55:
56: public function isSuperTypeOf(Type $type): TrinaryLogic
57: {
58: if ($type instanceof CompoundType) {
59: return $type->isSubTypeOf($this);
60: }
61:
62: if ($this->equals($type)) {
63: return TrinaryLogic::createYes();
64: }
65:
66: if ($type->isNonFalsyString()->yes()) {
67: return TrinaryLogic::createYes();
68: }
69:
70: return $type->isNonEmptyString();
71: }
72:
73: public function isSubTypeOf(Type $otherType): TrinaryLogic
74: {
75: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
76: return $otherType->isSuperTypeOf($this);
77: }
78:
79: return $otherType->isNonEmptyString()
80: ->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe());
81: }
82:
83: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic
84: {
85: return $this->isSubTypeOf($acceptingType);
86: }
87:
88: public function equals(Type $type): bool
89: {
90: return $type instanceof self;
91: }
92:
93: public function describe(VerbosityLevel $level): string
94: {
95: return 'non-empty-string';
96: }
97:
98: public function isOffsetAccessible(): TrinaryLogic
99: {
100: return TrinaryLogic::createYes();
101: }
102:
103: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
104: {
105: return (new IntegerType())->isSuperTypeOf($offsetType)->and(TrinaryLogic::createMaybe());
106: }
107:
108: public function getOffsetValueType(Type $offsetType): Type
109: {
110: if ($this->hasOffsetValueType($offsetType)->no()) {
111: return new ErrorType();
112: }
113:
114: if ((new ConstantIntegerType(0))->isSuperTypeOf($offsetType)->yes()) {
115: return new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]);
116: }
117:
118: return new StringType();
119: }
120:
121: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
122: {
123: return $this;
124: }
125:
126: public function unsetOffset(Type $offsetType): Type
127: {
128: return new ErrorType();
129: }
130:
131: public function isArray(): TrinaryLogic
132: {
133: return TrinaryLogic::createNo();
134: }
135:
136: public function isOversizedArray(): TrinaryLogic
137: {
138: return TrinaryLogic::createNo();
139: }
140:
141: public function toNumber(): Type
142: {
143: return new ErrorType();
144: }
145:
146: public function toInteger(): Type
147: {
148: return new IntegerType();
149: }
150:
151: public function toFloat(): Type
152: {
153: return new FloatType();
154: }
155:
156: public function toString(): Type
157: {
158: return $this;
159: }
160:
161: public function toArray(): Type
162: {
163: return new ConstantArrayType(
164: [new ConstantIntegerType(0)],
165: [$this],
166: [1],
167: );
168: }
169:
170: public function isString(): TrinaryLogic
171: {
172: return TrinaryLogic::createYes();
173: }
174:
175: public function isNumericString(): TrinaryLogic
176: {
177: return TrinaryLogic::createMaybe();
178: }
179:
180: public function isNonEmptyString(): TrinaryLogic
181: {
182: return TrinaryLogic::createYes();
183: }
184:
185: public function isNonFalsyString(): TrinaryLogic
186: {
187: return TrinaryLogic::createMaybe();
188: }
189:
190: public function isLiteralString(): TrinaryLogic
191: {
192: return TrinaryLogic::createMaybe();
193: }
194:
195: public function traverse(callable $cb): Type
196: {
197: return $this;
198: }
199:
200: public function generalize(GeneralizePrecision $precision): Type
201: {
202: return new StringType();
203: }
204:
205: public static function __set_state(array $properties): Type
206: {
207: return new self();
208: }
209:
210: public function tryRemove(Type $typeToRemove): ?Type
211: {
212: if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') {
213: return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType());
214: }
215:
216: return null;
217: }
218:
219: }
220: