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\ArrayType;
11: use PHPStan\Type\BooleanType;
12: use PHPStan\Type\CompoundType;
13: use PHPStan\Type\Constant\ConstantFloatType;
14: use PHPStan\Type\Constant\ConstantIntegerType;
15: use PHPStan\Type\ErrorType;
16: use PHPStan\Type\InstanceofDeprecated;
17: use PHPStan\Type\IntegerRangeType;
18: use PHPStan\Type\IntersectionType;
19: use PHPStan\Type\IsSuperTypeOfResult;
20: use PHPStan\Type\MixedType;
21: use PHPStan\Type\Traits\MaybeCallableTypeTrait;
22: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
23: use PHPStan\Type\Traits\NonGenericTypeTrait;
24: use PHPStan\Type\Traits\NonObjectTypeTrait;
25: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
26: use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
27: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
28: use PHPStan\Type\Type;
29: use PHPStan\Type\UnionType;
30: use PHPStan\Type\VerbosityLevel;
31:
32: /** @api */
33: #[InstanceofDeprecated(insteadUse: 'Type::isList()')]
34: class AccessoryArrayListType implements CompoundType, AccessoryType
35: {
36:
37: use MaybeCallableTypeTrait;
38: use NonObjectTypeTrait;
39: use NonGenericTypeTrait;
40: use UndecidedBooleanTypeTrait;
41: use UndecidedComparisonCompoundTypeTrait;
42: use NonRemoveableTypeTrait;
43: use NonGeneralizableTypeTrait;
44:
45: /** @api */
46: public function __construct()
47: {
48: }
49:
50: public function getReferencedClasses(): array
51: {
52: return [];
53: }
54:
55: public function getObjectClassNames(): array
56: {
57: return [];
58: }
59:
60: public function getObjectClassReflections(): array
61: {
62: return [];
63: }
64:
65: public function getArrays(): array
66: {
67: return [];
68: }
69:
70: public function getConstantArrays(): 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: $isList = $type->isList();
83:
84: if ($isList->yes()) {
85: return AcceptsResult::createYes();
86: }
87:
88: if ($type instanceof CompoundType) {
89: return $type->isAcceptedBy($this, $strictTypes);
90: }
91:
92: return new AcceptsResult($isList, []);
93: }
94:
95: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
96: {
97: if ($this->equals($type)) {
98: return IsSuperTypeOfResult::createYes();
99: }
100:
101: if ($type instanceof CompoundType) {
102: return $type->isSubTypeOf($this);
103: }
104:
105: return new IsSuperTypeOfResult($type->isList(), []);
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 self) {
115: return new IsSuperTypeOfResult(
116: TrinaryLogic::createYes(),
117: [],
118: );
119: }
120:
121: return new IsSuperTypeOfResult(
122: $otherType->isList()->and(TrinaryLogic::createMaybe()),
123: [],
124: );
125: }
126:
127: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
128: {
129: return $this->isSubTypeOf($acceptingType)->toAcceptsResult();
130: }
131:
132: public function equals(Type $type): bool
133: {
134: return $type instanceof self;
135: }
136:
137: public function describe(VerbosityLevel $level): string
138: {
139: return 'list';
140: }
141:
142: public function isOffsetAccessible(): TrinaryLogic
143: {
144: return TrinaryLogic::createYes();
145: }
146:
147: public function isOffsetAccessLegal(): TrinaryLogic
148: {
149: return TrinaryLogic::createYes();
150: }
151:
152: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
153: {
154: return $this->getIterableKeyType()->isSuperTypeOf($offsetType)->result->and(TrinaryLogic::createMaybe());
155: }
156:
157: public function getOffsetValueType(Type $offsetType): Type
158: {
159: return new MixedType();
160: }
161:
162: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
163: {
164: if ($offsetType === null || (new ConstantIntegerType(0))->isSuperTypeOf($offsetType)->yes()) {
165: return $this;
166: }
167:
168: return new ErrorType();
169: }
170:
171: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
172: {
173: return $this;
174: }
175:
176: public function unsetOffset(Type $offsetType): Type
177: {
178: if ($this->hasOffsetValueType($offsetType)->no()) {
179: return $this;
180: }
181:
182: return new ErrorType();
183: }
184:
185: public function getKeysArrayFiltered(Type $filterValueType, TrinaryLogic $strict): Type
186: {
187: return $this->getKeysArray();
188: }
189:
190: public function getKeysArray(): Type
191: {
192: return $this;
193: }
194:
195: public function getValuesArray(): Type
196: {
197: return $this;
198: }
199:
200: public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
201: {
202: return $this;
203: }
204:
205: public function fillKeysArray(Type $valueType): Type
206: {
207: return new MixedType();
208: }
209:
210: public function flipArray(): Type
211: {
212: return new MixedType();
213: }
214:
215: public function intersectKeyArray(Type $otherArraysType): Type
216: {
217: if ($otherArraysType->isList()->yes()) {
218: return $this;
219: }
220:
221: return new MixedType();
222: }
223:
224: public function popArray(): Type
225: {
226: return $this;
227: }
228:
229: public function reverseArray(TrinaryLogic $preserveKeys): Type
230: {
231: if ($preserveKeys->no()) {
232: return $this;
233: }
234:
235: return new MixedType();
236: }
237:
238: public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
239: {
240: return new MixedType();
241: }
242:
243: public function shiftArray(): Type
244: {
245: return $this;
246: }
247:
248: public function shuffleArray(): Type
249: {
250: return $this;
251: }
252:
253: public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type
254: {
255: if ($preserveKeys->no()) {
256: return $this;
257: }
258:
259: if ((new ConstantIntegerType(0))->isSuperTypeOf($offsetType)->yes()) {
260: return $this;
261: }
262:
263: return new MixedType();
264: }
265:
266: public function spliceArray(Type $offsetType, Type $lengthType, Type $replacementType): Type
267: {
268: return $this;
269: }
270:
271: public function truncateListToSize(Type $sizeType): Type
272: {
273: // List-ness survives a count narrowing — the resulting array is
274: // still a list, just of a constrained size.
275: return $this;
276: }
277:
278: public function makeListMaybe(): Type
279: {
280: // This accessory is the list assertion itself; weakening the
281: // list-ness to "maybe" means the accessory no longer applies.
282: // Returning `MixedType` lets the enclosing `IntersectionType` drop
283: // it via `TypeCombinator::intersect` while preserving the rest.
284: return new MixedType();
285: }
286:
287: public function mapValueType(callable $cb): Type
288: {
289: // Mapping values doesn't disturb list-ness.
290: return $this;
291: }
292:
293: public function mapKeyType(callable $cb): Type
294: {
295: return $this;
296: }
297:
298: public function makeAllArrayKeysOptional(): Type
299: {
300: // Marking keys optional in an arbitrary list keeps it a list.
301: return $this;
302: }
303:
304: public function changeKeyCaseArray(?int $case): Type
305: {
306: // List keys are integers; case-folding leaves them alone.
307: return $this;
308: }
309:
310: public function filterArrayRemovingFalsey(): Type
311: {
312: // Filtering creates gaps in the integer-key sequence — list-ness lost.
313: return new MixedType();
314: }
315:
316: public function isIterable(): TrinaryLogic
317: {
318: return TrinaryLogic::createYes();
319: }
320:
321: public function isIterableAtLeastOnce(): TrinaryLogic
322: {
323: return TrinaryLogic::createMaybe();
324: }
325:
326: public function getArraySize(): Type
327: {
328: return IntegerRangeType::fromInterval(0, null);
329: }
330:
331: public function getIterableKeyType(): Type
332: {
333: return IntegerRangeType::fromInterval(0, null);
334: }
335:
336: public function getFirstIterableKeyType(): Type
337: {
338: return new ConstantIntegerType(0);
339: }
340:
341: public function getLastIterableKeyType(): Type
342: {
343: return $this->getIterableKeyType();
344: }
345:
346: public function getIterableValueType(): Type
347: {
348: return new MixedType();
349: }
350:
351: public function getFirstIterableValueType(): Type
352: {
353: return new MixedType();
354: }
355:
356: public function getLastIterableValueType(): Type
357: {
358: return new MixedType();
359: }
360:
361: public function isArray(): TrinaryLogic
362: {
363: return TrinaryLogic::createYes();
364: }
365:
366: public function isConstantArray(): TrinaryLogic
367: {
368: return TrinaryLogic::createMaybe();
369: }
370:
371: public function isOversizedArray(): TrinaryLogic
372: {
373: return TrinaryLogic::createMaybe();
374: }
375:
376: public function isList(): TrinaryLogic
377: {
378: return TrinaryLogic::createYes();
379: }
380:
381: public function isNull(): TrinaryLogic
382: {
383: return TrinaryLogic::createNo();
384: }
385:
386: public function isConstantValue(): TrinaryLogic
387: {
388: return TrinaryLogic::createMaybe();
389: }
390:
391: public function isConstantScalarValue(): TrinaryLogic
392: {
393: return TrinaryLogic::createNo();
394: }
395:
396: public function getConstantScalarTypes(): array
397: {
398: return [];
399: }
400:
401: public function getConstantScalarValues(): array
402: {
403: return [];
404: }
405:
406: public function isTrue(): TrinaryLogic
407: {
408: return TrinaryLogic::createNo();
409: }
410:
411: public function isFalse(): TrinaryLogic
412: {
413: return TrinaryLogic::createNo();
414: }
415:
416: public function isBoolean(): TrinaryLogic
417: {
418: return TrinaryLogic::createNo();
419: }
420:
421: public function isFloat(): TrinaryLogic
422: {
423: return TrinaryLogic::createNo();
424: }
425:
426: public function isInteger(): TrinaryLogic
427: {
428: return TrinaryLogic::createNo();
429: }
430:
431: public function isString(): TrinaryLogic
432: {
433: return TrinaryLogic::createNo();
434: }
435:
436: public function isNumericString(): TrinaryLogic
437: {
438: return TrinaryLogic::createNo();
439: }
440:
441: public function isDecimalIntegerString(): TrinaryLogic
442: {
443: return TrinaryLogic::createNo();
444: }
445:
446: public function isNonEmptyString(): TrinaryLogic
447: {
448: return TrinaryLogic::createNo();
449: }
450:
451: public function isNonFalsyString(): TrinaryLogic
452: {
453: return TrinaryLogic::createNo();
454: }
455:
456: public function isLiteralString(): TrinaryLogic
457: {
458: return TrinaryLogic::createNo();
459: }
460:
461: public function isLowercaseString(): TrinaryLogic
462: {
463: return TrinaryLogic::createNo();
464: }
465:
466: public function isClassString(): TrinaryLogic
467: {
468: return TrinaryLogic::createNo();
469: }
470:
471: public function isUppercaseString(): TrinaryLogic
472: {
473: return TrinaryLogic::createNo();
474: }
475:
476: public function getClassStringObjectType(): Type
477: {
478: return new ErrorType();
479: }
480:
481: public function getObjectTypeOrClassStringObjectType(): Type
482: {
483: return new ErrorType();
484: }
485:
486: public function isVoid(): TrinaryLogic
487: {
488: return TrinaryLogic::createNo();
489: }
490:
491: public function isScalar(): TrinaryLogic
492: {
493: return TrinaryLogic::createNo();
494: }
495:
496: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
497: {
498: return new BooleanType();
499: }
500:
501: public function toNumber(): Type
502: {
503: return new ErrorType();
504: }
505:
506: public function toBitwiseNotType(): Type
507: {
508: return new ErrorType();
509: }
510:
511: public function toAbsoluteNumber(): Type
512: {
513: return new ErrorType();
514: }
515:
516: public function toInteger(): Type
517: {
518: return new UnionType([
519: new ConstantIntegerType(0),
520: new ConstantIntegerType(1),
521: ]);
522: }
523:
524: public function toFloat(): Type
525: {
526: return new UnionType([
527: new ConstantFloatType(0.0),
528: new ConstantFloatType(1.0),
529: ]);
530: }
531:
532: public function toString(): Type
533: {
534: return new ErrorType();
535: }
536:
537: public function toArray(): Type
538: {
539: return $this;
540: }
541:
542: public function toArrayKey(): Type
543: {
544: return new ErrorType();
545: }
546:
547: public function toCoercedArgumentType(bool $strictTypes): Type
548: {
549: return $this;
550: }
551:
552: public function traverse(callable $cb): Type
553: {
554: return $this;
555: }
556:
557: public function traverseSimultaneously(Type $right, callable $cb): Type
558: {
559: return $this;
560: }
561:
562: public function exponentiate(Type $exponent): Type
563: {
564: return new ErrorType();
565: }
566:
567: public function getFiniteTypes(): array
568: {
569: return [];
570: }
571:
572: public function getDefaultBaseType(): Type
573: {
574: return new ArrayType(new MixedType(), new MixedType());
575: }
576:
577: public function toPhpDocNode(): TypeNode
578: {
579: return new IdentifierTypeNode('list');
580: }
581:
582: public function hasTemplateOrLateResolvableType(): bool
583: {
584: return false;
585: }
586:
587: }
588: