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\Type\AcceptsResult;
10: use PHPStan\Type\BooleanType;
11: use PHPStan\Type\CompoundType;
12: use PHPStan\Type\Constant\ConstantBooleanType;
13: use PHPStan\Type\Constant\ConstantFloatType;
14: use PHPStan\Type\Constant\ConstantIntegerType;
15: use PHPStan\Type\ErrorType;
16: use PHPStan\Type\IntegerRangeType;
17: use PHPStan\Type\IntersectionType;
18: use PHPStan\Type\IsSuperTypeOfResult;
19: use PHPStan\Type\MixedType;
20: use PHPStan\Type\Traits\MaybeCallableTypeTrait;
21: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
22: use PHPStan\Type\Traits\NonGenericTypeTrait;
23: use PHPStan\Type\Traits\NonObjectTypeTrait;
24: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
25: use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
26: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
27: use PHPStan\Type\Type;
28: use PHPStan\Type\UnionType;
29: use PHPStan\Type\VerbosityLevel;
30:
31: class NonEmptyArrayType implements CompoundType, AccessoryType
32: {
33:
34: use MaybeCallableTypeTrait;
35: use NonObjectTypeTrait;
36: use TruthyBooleanTypeTrait;
37: use NonGenericTypeTrait;
38: use UndecidedComparisonCompoundTypeTrait;
39: use NonRemoveableTypeTrait;
40: use NonGeneralizableTypeTrait;
41:
42: /** @api */
43: public function __construct()
44: {
45: }
46:
47: public function getReferencedClasses(): array
48: {
49: return [];
50: }
51:
52: public function getObjectClassNames(): array
53: {
54: return [];
55: }
56:
57: public function getObjectClassReflections(): array
58: {
59: return [];
60: }
61:
62: public function getArrays(): array
63: {
64: return [];
65: }
66:
67: public function getConstantArrays(): array
68: {
69: return [];
70: }
71:
72: public function getConstantStrings(): array
73: {
74: return [];
75: }
76:
77: public function accepts(Type $type, bool $strictTypes): AcceptsResult
78: {
79: $isArray = $type->isArray();
80: $isIterableAtLeastOnce = $type->isIterableAtLeastOnce();
81: $isNonEmptyArray = $isArray->and($isIterableAtLeastOnce);
82:
83: if ($isNonEmptyArray->yes()) {
84: return AcceptsResult::createYes();
85: }
86:
87: if ($type instanceof CompoundType) {
88: return $type->isAcceptedBy($this, $strictTypes);
89: }
90:
91: return new AcceptsResult($isNonEmptyArray, []);
92: }
93:
94: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
95: {
96: if ($this->equals($type)) {
97: return IsSuperTypeOfResult::createYes();
98: }
99:
100: if ($type instanceof CompoundType) {
101: return $type->isSubTypeOf($this);
102: }
103:
104: return new IsSuperTypeOfResult($type->isArray()->and($type->isIterableAtLeastOnce()), []);
105: }
106:
107: public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
108: {
109: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
110: return $otherType->isSuperTypeOf($this);
111: }
112:
113: return new IsSuperTypeOfResult(
114: $otherType->isArray()->and($otherType->isIterableAtLeastOnce())->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe()),
115: [],
116: );
117: }
118:
119: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
120: {
121: return $this->isSubTypeOf($acceptingType)->toAcceptsResult();
122: }
123:
124: public function equals(Type $type): bool
125: {
126: return $type instanceof self;
127: }
128:
129: public function describe(VerbosityLevel $level): string
130: {
131: return 'non-empty-array';
132: }
133:
134: public function isOffsetAccessible(): TrinaryLogic
135: {
136: return TrinaryLogic::createYes();
137: }
138:
139: public function isOffsetAccessLegal(): TrinaryLogic
140: {
141: return TrinaryLogic::createYes();
142: }
143:
144: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
145: {
146: return TrinaryLogic::createMaybe();
147: }
148:
149: public function getOffsetValueType(Type $offsetType): Type
150: {
151: return new MixedType();
152: }
153:
154: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
155: {
156: return $this;
157: }
158:
159: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
160: {
161: return $this;
162: }
163:
164: public function unsetOffset(Type $offsetType): Type
165: {
166: return new ErrorType();
167: }
168:
169: public function getKeysArrayFiltered(Type $filterValueType, TrinaryLogic $strict): Type
170: {
171: return new ErrorType();
172: }
173:
174: public function getKeysArray(): Type
175: {
176: return $this;
177: }
178:
179: public function getValuesArray(): Type
180: {
181: return $this;
182: }
183:
184: public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
185: {
186: return $this;
187: }
188:
189: public function fillKeysArray(Type $valueType): Type
190: {
191: return $this;
192: }
193:
194: public function flipArray(): Type
195: {
196: return $this;
197: }
198:
199: public function intersectKeyArray(Type $otherArraysType): Type
200: {
201: return new MixedType();
202: }
203:
204: public function popArray(): Type
205: {
206: return new MixedType();
207: }
208:
209: public function reverseArray(TrinaryLogic $preserveKeys): Type
210: {
211: return $this;
212: }
213:
214: public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
215: {
216: return new MixedType();
217: }
218:
219: public function shiftArray(): Type
220: {
221: return new MixedType();
222: }
223:
224: public function shuffleArray(): Type
225: {
226: return $this;
227: }
228:
229: public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type
230: {
231: if ((new ConstantIntegerType(0))->isSuperTypeOf($offsetType)->yes() && $lengthType->isNull()->yes()) {
232: return $this;
233: }
234:
235: return new MixedType();
236: }
237:
238: public function spliceArray(Type $offsetType, Type $lengthType, Type $replacementType): Type
239: {
240: if (
241: (new ConstantIntegerType(0))->isSuperTypeOf($lengthType)->yes()
242: || $replacementType->toArray()->isIterableAtLeastOnce()->yes()
243: ) {
244: return $this;
245: }
246:
247: return new MixedType();
248: }
249:
250: public function isIterable(): TrinaryLogic
251: {
252: return TrinaryLogic::createYes();
253: }
254:
255: public function isIterableAtLeastOnce(): TrinaryLogic
256: {
257: return TrinaryLogic::createYes();
258: }
259:
260: public function getArraySize(): Type
261: {
262: return IntegerRangeType::fromInterval(1, null);
263: }
264:
265: public function getIterableKeyType(): Type
266: {
267: return new MixedType();
268: }
269:
270: public function getFirstIterableKeyType(): Type
271: {
272: return new MixedType();
273: }
274:
275: public function getLastIterableKeyType(): Type
276: {
277: return new MixedType();
278: }
279:
280: public function getIterableValueType(): Type
281: {
282: return new MixedType();
283: }
284:
285: public function getFirstIterableValueType(): Type
286: {
287: return new MixedType();
288: }
289:
290: public function getLastIterableValueType(): Type
291: {
292: return new MixedType();
293: }
294:
295: public function isArray(): TrinaryLogic
296: {
297: return TrinaryLogic::createYes();
298: }
299:
300: public function isConstantArray(): TrinaryLogic
301: {
302: return TrinaryLogic::createMaybe();
303: }
304:
305: public function isOversizedArray(): TrinaryLogic
306: {
307: return TrinaryLogic::createMaybe();
308: }
309:
310: public function isList(): TrinaryLogic
311: {
312: return TrinaryLogic::createMaybe();
313: }
314:
315: public function isNull(): TrinaryLogic
316: {
317: return TrinaryLogic::createNo();
318: }
319:
320: public function isConstantValue(): TrinaryLogic
321: {
322: return TrinaryLogic::createMaybe();
323: }
324:
325: public function isConstantScalarValue(): TrinaryLogic
326: {
327: return TrinaryLogic::createNo();
328: }
329:
330: public function getConstantScalarTypes(): array
331: {
332: return [];
333: }
334:
335: public function getConstantScalarValues(): array
336: {
337: return [];
338: }
339:
340: public function isTrue(): TrinaryLogic
341: {
342: return TrinaryLogic::createNo();
343: }
344:
345: public function isFalse(): TrinaryLogic
346: {
347: return TrinaryLogic::createNo();
348: }
349:
350: public function isBoolean(): TrinaryLogic
351: {
352: return TrinaryLogic::createNo();
353: }
354:
355: public function isFloat(): TrinaryLogic
356: {
357: return TrinaryLogic::createNo();
358: }
359:
360: public function isInteger(): TrinaryLogic
361: {
362: return TrinaryLogic::createNo();
363: }
364:
365: public function isString(): TrinaryLogic
366: {
367: return TrinaryLogic::createNo();
368: }
369:
370: public function isNumericString(): TrinaryLogic
371: {
372: return TrinaryLogic::createNo();
373: }
374:
375: public function isNonEmptyString(): TrinaryLogic
376: {
377: return TrinaryLogic::createNo();
378: }
379:
380: public function isNonFalsyString(): TrinaryLogic
381: {
382: return TrinaryLogic::createNo();
383: }
384:
385: public function isLiteralString(): TrinaryLogic
386: {
387: return TrinaryLogic::createNo();
388: }
389:
390: public function isLowercaseString(): TrinaryLogic
391: {
392: return TrinaryLogic::createNo();
393: }
394:
395: public function isClassString(): TrinaryLogic
396: {
397: return TrinaryLogic::createNo();
398: }
399:
400: public function isUppercaseString(): TrinaryLogic
401: {
402: return TrinaryLogic::createNo();
403: }
404:
405: public function getClassStringObjectType(): Type
406: {
407: return new ErrorType();
408: }
409:
410: public function getObjectTypeOrClassStringObjectType(): Type
411: {
412: return new ErrorType();
413: }
414:
415: public function isVoid(): TrinaryLogic
416: {
417: return TrinaryLogic::createNo();
418: }
419:
420: public function isScalar(): TrinaryLogic
421: {
422: return TrinaryLogic::createNo();
423: }
424:
425: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
426: {
427: if ($type->isArray()->yes() && $type->isIterableAtLeastOnce()->no()) {
428: return new ConstantBooleanType(false);
429: }
430:
431: return new BooleanType();
432: }
433:
434: public function toNumber(): Type
435: {
436: return new ErrorType();
437: }
438:
439: public function toAbsoluteNumber(): Type
440: {
441: return new ErrorType();
442: }
443:
444: public function toInteger(): Type
445: {
446: return new ConstantIntegerType(1);
447: }
448:
449: public function toFloat(): Type
450: {
451: return new ConstantFloatType(1.0);
452: }
453:
454: public function toString(): Type
455: {
456: return new ErrorType();
457: }
458:
459: public function toArray(): Type
460: {
461: return $this;
462: }
463:
464: public function toArrayKey(): Type
465: {
466: return new ErrorType();
467: }
468:
469: public function toCoercedArgumentType(bool $strictTypes): Type
470: {
471: return $this;
472: }
473:
474: public function traverse(callable $cb): Type
475: {
476: return $this;
477: }
478:
479: public function traverseSimultaneously(Type $right, callable $cb): Type
480: {
481: return $this;
482: }
483:
484: public function exponentiate(Type $exponent): Type
485: {
486: return new ErrorType();
487: }
488:
489: public function getFiniteTypes(): array
490: {
491: return [];
492: }
493:
494: public function toPhpDocNode(): TypeNode
495: {
496: return new IdentifierTypeNode('non-empty-array');
497: }
498:
499: public function hasTemplateOrLateResolvableType(): bool
500: {
501: return false;
502: }
503:
504: }
505: