1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\Php\PhpVersion;
6: use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
8: use PHPStan\TrinaryLogic;
9: use PHPStan\Turbo\ShadowedByTurboExtension;
10: use PHPStan\Type\AcceptsResult;
11: use PHPStan\Type\BenevolentUnionType;
12: use PHPStan\Type\BooleanType;
13: use PHPStan\Type\CompoundType;
14: use PHPStan\Type\Constant\ConstantArrayType;
15: use PHPStan\Type\Constant\ConstantBooleanType;
16: use PHPStan\Type\Constant\ConstantIntegerType;
17: use PHPStan\Type\Constant\ConstantStringType;
18: use PHPStan\Type\ErrorType;
19: use PHPStan\Type\FloatType;
20: use PHPStan\Type\GeneralizePrecision;
21: use PHPStan\Type\InstanceofDeprecated;
22: use PHPStan\Type\IntegerType;
23: use PHPStan\Type\IntersectionType;
24: use PHPStan\Type\IsSuperTypeOfResult;
25: use PHPStan\Type\NullType;
26: use PHPStan\Type\ObjectWithoutClassType;
27: use PHPStan\Type\StringType;
28: use PHPStan\Type\Traits\MaybeCallableTypeTrait;
29: use PHPStan\Type\Traits\NonArrayTypeTrait;
30: use PHPStan\Type\Traits\NonGenericTypeTrait;
31: use PHPStan\Type\Traits\NonIterableTypeTrait;
32: use PHPStan\Type\Traits\NonObjectTypeTrait;
33: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
34: use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
35: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
36: use PHPStan\Type\Type;
37: use PHPStan\Type\TypeCombinator;
38: use PHPStan\Type\UnionType;
39: use PHPStan\Type\VerbosityLevel;
40:
41: #[InstanceofDeprecated(insteadUse: 'Type::isNonFalsyString()')]
42: #[ShadowedByTurboExtension(implementation: __DIR__ . '/../../../turbo-ext/src/AccessoryNonFalsyStringType.cpp')]
43: class AccessoryNonFalsyStringType implements CompoundType, AccessoryType
44: {
45:
46: use MaybeCallableTypeTrait;
47: use NonArrayTypeTrait;
48: use NonObjectTypeTrait;
49: use NonIterableTypeTrait;
50: use TruthyBooleanTypeTrait;
51: use UndecidedComparisonCompoundTypeTrait;
52: use NonGenericTypeTrait;
53: use NonRemoveableTypeTrait;
54:
55: /** @api */
56: public function __construct()
57: {
58: }
59:
60: public function getReferencedClasses(): array
61: {
62: return [];
63: }
64:
65: public function getObjectClassNames(): array
66: {
67: return [];
68: }
69:
70: public function getObjectClassReflections(): array
71: {
72: return [];
73: }
74:
75: public function getConstantStrings(): array
76: {
77: return [];
78: }
79:
80: public function accepts(Type $type, bool $strictTypes): AcceptsResult
81: {
82: $isNonFalsyString = $type->isNonFalsyString();
83:
84: if ($isNonFalsyString->yes()) {
85: return AcceptsResult::createYes();
86: }
87:
88: if ($type instanceof CompoundType) {
89: return $type->isAcceptedBy($this, $strictTypes);
90: }
91:
92: return new AcceptsResult($isNonFalsyString, []);
93: }
94:
95: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
96: {
97: if ($type instanceof CompoundType) {
98: return $type->isSubTypeOf($this);
99: }
100:
101: if ($this->equals($type)) {
102: return IsSuperTypeOfResult::createYes();
103: }
104:
105: return new IsSuperTypeOfResult($type->isNonFalsyString(), []);
106: }
107:
108: public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
109: {
110: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
111: return $otherType->isSuperTypeOf($this);
112: }
113:
114: if ($otherType instanceof AccessoryNonEmptyStringType) {
115: return IsSuperTypeOfResult::createYes();
116: }
117:
118: return new IsSuperTypeOfResult(
119: $otherType->isNonFalsyString()->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe()),
120: [],
121: );
122: }
123:
124: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
125: {
126: return $this->isSubTypeOf($acceptingType)->toAcceptsResult();
127: }
128:
129: public function equals(Type $type): bool
130: {
131: return $type instanceof self;
132: }
133:
134: public function describe(VerbosityLevel $level): string
135: {
136: return 'non-falsy-string';
137: }
138:
139: public function isOffsetAccessible(): TrinaryLogic
140: {
141: return TrinaryLogic::createYes();
142: }
143:
144: public function isOffsetAccessLegal(): TrinaryLogic
145: {
146: return TrinaryLogic::createYes();
147: }
148:
149: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
150: {
151: return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
152: }
153:
154: public function getOffsetValueType(Type $offsetType): Type
155: {
156: if ($this->hasOffsetValueType($offsetType)->no()) {
157: return new ErrorType();
158: }
159:
160: return new StringType();
161: }
162:
163: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
164: {
165: $stringOffset = (new StringType())->setOffsetValueType($offsetType, $valueType, $unionValues);
166:
167: if ($stringOffset instanceof ErrorType) {
168: return $stringOffset;
169: }
170:
171: if ($valueType->isNonFalsyString()->yes()) {
172: return $this;
173: }
174:
175: return new StringType();
176: }
177:
178: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
179: {
180: return $this;
181: }
182:
183: public function unsetOffset(Type $offsetType): Type
184: {
185: return new ErrorType();
186: }
187:
188: public function toNumber(): Type
189: {
190: return new ErrorType();
191: }
192:
193: public function toBitwiseNotType(): Type
194: {
195: return new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]);
196: }
197:
198: public function toAbsoluteNumber(): Type
199: {
200: return new ErrorType();
201: }
202:
203: public function toInteger(): Type
204: {
205: // Do not remove `0` since `(int) '00'` is still `0`.
206: return new IntegerType();
207: }
208:
209: public function toFloat(): Type
210: {
211: return new FloatType();
212: }
213:
214: public function toString(): Type
215: {
216: return $this;
217: }
218:
219: public function toArray(): Type
220: {
221: return new ConstantArrayType(
222: [new ConstantIntegerType(0)],
223: [$this],
224: [1],
225: isList: TrinaryLogic::createYes(),
226: );
227: }
228:
229: public function toArrayKey(): Type
230: {
231: return $this;
232: }
233:
234: public function toCoercedArgumentType(bool $strictTypes): Type
235: {
236: if (!$strictTypes) {
237: return TypeCombinator::union($this->toInteger(), $this->toFloat(), $this, $this->toBoolean());
238: }
239:
240: return $this;
241: }
242:
243: public function isNull(): TrinaryLogic
244: {
245: return TrinaryLogic::createNo();
246: }
247:
248: public function isConstantValue(): TrinaryLogic
249: {
250: return TrinaryLogic::createMaybe();
251: }
252:
253: public function isConstantScalarValue(): TrinaryLogic
254: {
255: return TrinaryLogic::createMaybe();
256: }
257:
258: public function getConstantScalarTypes(): array
259: {
260: return [];
261: }
262:
263: public function getConstantScalarValues(): array
264: {
265: return [];
266: }
267:
268: public function isTrue(): TrinaryLogic
269: {
270: return TrinaryLogic::createNo();
271: }
272:
273: public function isFalse(): TrinaryLogic
274: {
275: return TrinaryLogic::createNo();
276: }
277:
278: public function isBoolean(): TrinaryLogic
279: {
280: return TrinaryLogic::createNo();
281: }
282:
283: public function isFloat(): TrinaryLogic
284: {
285: return TrinaryLogic::createNo();
286: }
287:
288: public function isInteger(): TrinaryLogic
289: {
290: return TrinaryLogic::createNo();
291: }
292:
293: public function isString(): TrinaryLogic
294: {
295: return TrinaryLogic::createYes();
296: }
297:
298: public function isNumericString(): TrinaryLogic
299: {
300: return TrinaryLogic::createMaybe();
301: }
302:
303: public function isDecimalIntegerString(): TrinaryLogic
304: {
305: return TrinaryLogic::createMaybe();
306: }
307:
308: public function isNonEmptyString(): TrinaryLogic
309: {
310: return TrinaryLogic::createYes();
311: }
312:
313: public function isNonFalsyString(): TrinaryLogic
314: {
315: return TrinaryLogic::createYes();
316: }
317:
318: public function isLiteralString(): TrinaryLogic
319: {
320: return TrinaryLogic::createMaybe();
321: }
322:
323: public function isLowercaseString(): TrinaryLogic
324: {
325: return TrinaryLogic::createMaybe();
326: }
327:
328: public function isClassString(): TrinaryLogic
329: {
330: return TrinaryLogic::createMaybe();
331: }
332:
333: public function isUppercaseString(): TrinaryLogic
334: {
335: return TrinaryLogic::createMaybe();
336: }
337:
338: public function getClassStringObjectType(): Type
339: {
340: return new ObjectWithoutClassType();
341: }
342:
343: public function getObjectTypeOrClassStringObjectType(): Type
344: {
345: return new ObjectWithoutClassType();
346: }
347:
348: public function isVoid(): TrinaryLogic
349: {
350: return TrinaryLogic::createNo();
351: }
352:
353: public function isScalar(): TrinaryLogic
354: {
355: return TrinaryLogic::createYes();
356: }
357:
358: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
359: {
360: $dominated = TypeCombinator::union(
361: new NullType(),
362: new ConstantBooleanType(false),
363: new ConstantStringType(''),
364: new ConstantArrayType([], []),
365: );
366: if ($dominated->isSuperTypeOf($type)->yes()) {
367: return new ConstantBooleanType(false);
368: }
369:
370: return new BooleanType();
371: }
372:
373: public function traverse(callable $cb): Type
374: {
375: return $this;
376: }
377:
378: public function traverseSimultaneously(Type $right, callable $cb): Type
379: {
380: return $this;
381: }
382:
383: public function generalize(GeneralizePrecision $precision): Type
384: {
385: return new StringType();
386: }
387:
388: public function exponentiate(Type $exponent): Type
389: {
390: return new BenevolentUnionType([
391: new FloatType(),
392: new IntegerType(),
393: ]);
394: }
395:
396: public function getFiniteTypes(): array
397: {
398: return [];
399: }
400:
401: public function getDefaultBaseType(): Type
402: {
403: return new StringType();
404: }
405:
406: public function toPhpDocNode(): TypeNode
407: {
408: return new IdentifierTypeNode('non-falsy-string');
409: }
410:
411: public function hasTemplateOrLateResolvableType(): bool
412: {
413: return false;
414: }
415:
416: }
417: