1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Traits;
4:
5: use PHPStan\Php\PhpVersion;
6: use PHPStan\Reflection\ClassConstantReflection;
7: use PHPStan\Reflection\ClassMemberAccessAnswerer;
8: use PHPStan\Reflection\ExtendedMethodReflection;
9: use PHPStan\Reflection\ExtendedPropertyReflection;
10: use PHPStan\Reflection\ReflectionProvider;
11: use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection;
12: use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
13: use PHPStan\TrinaryLogic;
14: use PHPStan\Type\AcceptsResult;
15: use PHPStan\Type\BooleanType;
16: use PHPStan\Type\ClassNameToObjectTypeResult;
17: use PHPStan\Type\CompoundType;
18: use PHPStan\Type\Enum\EnumCaseObjectType;
19: use PHPStan\Type\Generic\TemplateTypeMap;
20: use PHPStan\Type\IsSuperTypeOfResult;
21: use PHPStan\Type\LateResolvableType;
22: use PHPStan\Type\NativeTypePosition;
23: use PHPStan\Type\NeverType;
24: use PHPStan\Type\Type;
25:
26: /** @api */
27: trait LateResolvableTypeTrait
28: {
29:
30: private ?Type $result = null;
31:
32: public function getObjectClassNames(): array
33: {
34: return $this->resolve()->getObjectClassNames();
35: }
36:
37: public function getObjectClassReflections(): array
38: {
39: return $this->resolve()->getObjectClassReflections();
40: }
41:
42: public function getArrays(): array
43: {
44: return $this->resolve()->getArrays();
45: }
46:
47: public function getConstantArrays(): array
48: {
49: return $this->resolve()->getConstantArrays();
50: }
51:
52: public function getConstantStrings(): array
53: {
54: return $this->resolve()->getConstantStrings();
55: }
56:
57: public function accepts(Type $type, bool $strictTypes): AcceptsResult
58: {
59: return $this->resolve()->accepts($type, $strictTypes);
60: }
61:
62: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
63: {
64: return $this->isSuperTypeOfDefault($type);
65: }
66:
67: private function isSuperTypeOfDefault(Type $type): IsSuperTypeOfResult
68: {
69: if ($type instanceof NeverType) {
70: return IsSuperTypeOfResult::createYes();
71: }
72:
73: if ($type instanceof LateResolvableType) {
74: $type = $type->resolve();
75: }
76:
77: $isSuperType = $this->resolve()->isSuperTypeOf($type);
78:
79: if (!$this->isResolvable()) {
80: $isSuperType = $isSuperType->and(IsSuperTypeOfResult::createMaybe());
81: }
82:
83: return $isSuperType;
84: }
85:
86: public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
87: {
88: return $this->resolve()->getTemplateType($ancestorClassName, $templateTypeName);
89: }
90:
91: public function isObject(): TrinaryLogic
92: {
93: return $this->resolve()->isObject();
94: }
95:
96: public function getClassStringType(): Type
97: {
98: return $this->resolve()->getClassStringType();
99: }
100:
101: public function isEnum(): TrinaryLogic
102: {
103: return $this->resolve()->isEnum();
104: }
105:
106: public function canAccessProperties(): TrinaryLogic
107: {
108: return $this->resolve()->canAccessProperties();
109: }
110:
111: public function hasProperty(string $propertyName): TrinaryLogic
112: {
113: return $this->resolve()->hasProperty($propertyName);
114: }
115:
116: public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
117: {
118: return $this->resolve()->getProperty($propertyName, $scope);
119: }
120:
121: public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection
122: {
123: return $this->resolve()->getUnresolvedPropertyPrototype($propertyName, $scope);
124: }
125:
126: public function hasInstanceProperty(string $propertyName): TrinaryLogic
127: {
128: return $this->resolve()->hasInstanceProperty($propertyName);
129: }
130:
131: public function getInstanceProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
132: {
133: return $this->resolve()->getInstanceProperty($propertyName, $scope);
134: }
135:
136: public function getUnresolvedInstancePropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection
137: {
138: return $this->resolve()->getUnresolvedInstancePropertyPrototype($propertyName, $scope);
139: }
140:
141: public function hasStaticProperty(string $propertyName): TrinaryLogic
142: {
143: return $this->resolve()->hasStaticProperty($propertyName);
144: }
145:
146: public function getStaticProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
147: {
148: return $this->resolve()->getStaticProperty($propertyName, $scope);
149: }
150:
151: public function getUnresolvedStaticPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection
152: {
153: return $this->resolve()->getUnresolvedStaticPropertyPrototype($propertyName, $scope);
154: }
155:
156: public function canCallMethods(): TrinaryLogic
157: {
158: return $this->resolve()->canCallMethods();
159: }
160:
161: public function hasMethod(string $methodName): TrinaryLogic
162: {
163: return $this->resolve()->hasMethod($methodName);
164: }
165:
166: public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): ExtendedMethodReflection
167: {
168: return $this->resolve()->getMethod($methodName, $scope);
169: }
170:
171: public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection
172: {
173: return $this->resolve()->getUnresolvedMethodPrototype($methodName, $scope);
174: }
175:
176: public function canAccessConstants(): TrinaryLogic
177: {
178: return $this->resolve()->canAccessConstants();
179: }
180:
181: public function hasConstant(string $constantName): TrinaryLogic
182: {
183: return $this->resolve()->hasConstant($constantName);
184: }
185:
186: public function getConstant(string $constantName): ClassConstantReflection
187: {
188: return $this->resolve()->getConstant($constantName);
189: }
190:
191: public function isIterable(): TrinaryLogic
192: {
193: return $this->resolve()->isIterable();
194: }
195:
196: public function isIterableAtLeastOnce(): TrinaryLogic
197: {
198: return $this->resolve()->isIterableAtLeastOnce();
199: }
200:
201: public function getArraySize(): Type
202: {
203: return $this->resolve()->getArraySize();
204: }
205:
206: public function getIterableKeyType(): Type
207: {
208: return $this->resolve()->getIterableKeyType();
209: }
210:
211: public function getFirstIterableKeyType(): Type
212: {
213: return $this->resolve()->getIterableKeyType();
214: }
215:
216: public function getLastIterableKeyType(): Type
217: {
218: return $this->resolve()->getIterableKeyType();
219: }
220:
221: public function getIterableValueType(): Type
222: {
223: return $this->resolve()->getIterableValueType();
224: }
225:
226: public function getFirstIterableValueType(): Type
227: {
228: return $this->resolve()->getIterableValueType();
229: }
230:
231: public function getLastIterableValueType(): Type
232: {
233: return $this->resolve()->getIterableValueType();
234: }
235:
236: public function isArray(): TrinaryLogic
237: {
238: return $this->resolve()->isArray();
239: }
240:
241: public function isConstantArray(): TrinaryLogic
242: {
243: return $this->resolve()->isConstantArray();
244: }
245:
246: public function isOversizedArray(): TrinaryLogic
247: {
248: return $this->resolve()->isOversizedArray();
249: }
250:
251: public function isList(): TrinaryLogic
252: {
253: return $this->resolve()->isList();
254: }
255:
256: public function isOffsetAccessible(): TrinaryLogic
257: {
258: return $this->resolve()->isOffsetAccessible();
259: }
260:
261: public function isOffsetAccessLegal(): TrinaryLogic
262: {
263: return $this->resolve()->isOffsetAccessLegal();
264: }
265:
266: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
267: {
268: return $this->resolve()->hasOffsetValueType($offsetType);
269: }
270:
271: public function getOffsetValueType(Type $offsetType): Type
272: {
273: return $this->resolve()->getOffsetValueType($offsetType);
274: }
275:
276: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
277: {
278: return $this->resolve()->setOffsetValueType($offsetType, $valueType, $unionValues);
279: }
280:
281: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
282: {
283: return $this->resolve()->setExistingOffsetValueType($offsetType, $valueType);
284: }
285:
286: public function unsetOffset(Type $offsetType): Type
287: {
288: return $this->resolve()->unsetOffset($offsetType);
289: }
290:
291: public function getKeysArrayFiltered(Type $filterValueType, TrinaryLogic $strict): Type
292: {
293: return $this->resolve()->getKeysArrayFiltered($filterValueType, $strict);
294: }
295:
296: public function getKeysArray(): Type
297: {
298: return $this->resolve()->getKeysArray();
299: }
300:
301: public function getValuesArray(): Type
302: {
303: return $this->resolve()->getValuesArray();
304: }
305:
306: public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
307: {
308: return $this->resolve()->chunkArray($lengthType, $preserveKeys);
309: }
310:
311: public function fillKeysArray(Type $valueType): Type
312: {
313: return $this->resolve()->fillKeysArray($valueType);
314: }
315:
316: public function flipArray(): Type
317: {
318: return $this->resolve()->flipArray();
319: }
320:
321: public function intersectKeyArray(Type $otherArraysType): Type
322: {
323: return $this->resolve()->intersectKeyArray($otherArraysType);
324: }
325:
326: public function popArray(): Type
327: {
328: return $this->resolve()->popArray();
329: }
330:
331: public function reverseArray(TrinaryLogic $preserveKeys): Type
332: {
333: return $this->resolve()->reverseArray($preserveKeys);
334: }
335:
336: public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
337: {
338: return $this->resolve()->searchArray($needleType, $strict);
339: }
340:
341: public function shiftArray(): Type
342: {
343: return $this->resolve()->shiftArray();
344: }
345:
346: public function shuffleArray(): Type
347: {
348: return $this->resolve()->shuffleArray();
349: }
350:
351: public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type
352: {
353: return $this->resolve()->sliceArray($offsetType, $lengthType, $preserveKeys);
354: }
355:
356: public function spliceArray(Type $offsetType, Type $lengthType, Type $replacementType): Type
357: {
358: return $this->resolve()->spliceArray($offsetType, $lengthType, $replacementType);
359: }
360:
361: public function truncateListToSize(Type $sizeType): Type
362: {
363: return $this->resolve()->truncateListToSize($sizeType);
364: }
365:
366: public function makeListMaybe(): Type
367: {
368: return $this->resolve()->makeListMaybe();
369: }
370:
371: public function mapValueType(callable $cb): Type
372: {
373: return $this->resolve()->mapValueType($cb);
374: }
375:
376: public function mapKeyType(callable $cb): Type
377: {
378: return $this->resolve()->mapKeyType($cb);
379: }
380:
381: public function makeAllArrayKeysOptional(): Type
382: {
383: return $this->resolve()->makeAllArrayKeysOptional();
384: }
385:
386: public function changeKeyCaseArray(?int $case): Type
387: {
388: return $this->resolve()->changeKeyCaseArray($case);
389: }
390:
391: public function filterArrayRemovingFalsey(): Type
392: {
393: return $this->resolve()->filterArrayRemovingFalsey();
394: }
395:
396: public function isCallable(): TrinaryLogic
397: {
398: return $this->resolve()->isCallable();
399: }
400:
401: public function getEnumCases(): array
402: {
403: return $this->resolve()->getEnumCases();
404: }
405:
406: public function getEnumCaseObject(): ?EnumCaseObjectType
407: {
408: return $this->resolve()->getEnumCaseObject();
409: }
410:
411: public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array
412: {
413: return $this->resolve()->getCallableParametersAcceptors($scope);
414: }
415:
416: public function isCloneable(): TrinaryLogic
417: {
418: return $this->resolve()->isCloneable();
419: }
420:
421: public function toBoolean(): BooleanType
422: {
423: return $this->resolve()->toBoolean();
424: }
425:
426: public function toNumber(): Type
427: {
428: return $this->resolve()->toNumber();
429: }
430:
431: public function toBitwiseNotType(): Type
432: {
433: return $this->resolve()->toBitwiseNotType();
434: }
435:
436: public function toGetClassResultType(): Type
437: {
438: return $this->resolve()->toGetClassResultType();
439: }
440:
441: public function toClassConstantType(ReflectionProvider $reflectionProvider): Type
442: {
443: return $this->resolve()->toClassConstantType($reflectionProvider);
444: }
445:
446: public function toObjectTypeForInstanceofCheck(): ClassNameToObjectTypeResult
447: {
448: return $this->resolve()->toObjectTypeForInstanceofCheck();
449: }
450:
451: public function toObjectTypeForIsACheck(Type $objectOrClassType, bool $allowString, bool $allowSameClass): ClassNameToObjectTypeResult
452: {
453: return $this->resolve()->toObjectTypeForIsACheck($objectOrClassType, $allowString, $allowSameClass);
454: }
455:
456: public function toAbsoluteNumber(): Type
457: {
458: return $this->resolve()->toAbsoluteNumber();
459: }
460:
461: public function toInteger(): Type
462: {
463: return $this->resolve()->toInteger();
464: }
465:
466: public function toFloat(): Type
467: {
468: return $this->resolve()->toFloat();
469: }
470:
471: public function toString(): Type
472: {
473: return $this->resolve()->toString();
474: }
475:
476: public function toArray(): Type
477: {
478: return $this->resolve()->toArray();
479: }
480:
481: public function toArrayKey(): Type
482: {
483: return $this->resolve()->toArrayKey();
484: }
485:
486: public function toCoercedArgumentType(bool $strictTypes): Type
487: {
488: return $this->resolve()->toCoercedArgumentType($strictTypes);
489: }
490:
491: public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
492: {
493: return $this->resolve()->isSmallerThan($otherType, $phpVersion);
494: }
495:
496: public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
497: {
498: return $this->resolve()->isSmallerThanOrEqual($otherType, $phpVersion);
499: }
500:
501: public function isNull(): TrinaryLogic
502: {
503: return $this->resolve()->isNull();
504: }
505:
506: public function isConstantValue(): TrinaryLogic
507: {
508: return $this->resolve()->isConstantValue();
509: }
510:
511: public function isConstantScalarValue(): TrinaryLogic
512: {
513: return $this->resolve()->isConstantScalarValue();
514: }
515:
516: public function getConstantScalarTypes(): array
517: {
518: return $this->resolve()->getConstantScalarTypes();
519: }
520:
521: public function getConstantScalarValues(): array
522: {
523: return $this->resolve()->getConstantScalarValues();
524: }
525:
526: public function isTrue(): TrinaryLogic
527: {
528: return $this->resolve()->isTrue();
529: }
530:
531: public function isFalse(): TrinaryLogic
532: {
533: return $this->resolve()->isFalse();
534: }
535:
536: public function isBoolean(): TrinaryLogic
537: {
538: return $this->resolve()->isBoolean();
539: }
540:
541: public function isFloat(): TrinaryLogic
542: {
543: return $this->resolve()->isFloat();
544: }
545:
546: public function isInteger(): TrinaryLogic
547: {
548: return $this->resolve()->isInteger();
549: }
550:
551: public function isString(): TrinaryLogic
552: {
553: return $this->resolve()->isString();
554: }
555:
556: public function isNumericString(): TrinaryLogic
557: {
558: return $this->resolve()->isNumericString();
559: }
560:
561: public function isDecimalIntegerString(): TrinaryLogic
562: {
563: return $this->resolve()->isDecimalIntegerString();
564: }
565:
566: public function isNonEmptyString(): TrinaryLogic
567: {
568: return $this->resolve()->isNonEmptyString();
569: }
570:
571: public function isNonFalsyString(): TrinaryLogic
572: {
573: return $this->resolve()->isNonFalsyString();
574: }
575:
576: public function isLiteralString(): TrinaryLogic
577: {
578: return $this->resolve()->isLiteralString();
579: }
580:
581: public function isLowercaseString(): TrinaryLogic
582: {
583: return $this->resolve()->isLowercaseString();
584: }
585:
586: public function isUppercaseString(): TrinaryLogic
587: {
588: return $this->resolve()->isUppercaseString();
589: }
590:
591: public function isClassString(): TrinaryLogic
592: {
593: return $this->resolve()->isClassString();
594: }
595:
596: public function getClassStringObjectType(): Type
597: {
598: return $this->resolve()->getClassStringObjectType();
599: }
600:
601: public function getObjectTypeOrClassStringObjectType(): Type
602: {
603: return $this->resolve()->getObjectTypeOrClassStringObjectType();
604: }
605:
606: public function isVoid(): TrinaryLogic
607: {
608: return $this->resolve()->isVoid();
609: }
610:
611: public function isScalar(): TrinaryLogic
612: {
613: return $this->resolve()->isScalar();
614: }
615:
616: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
617: {
618: return new BooleanType();
619: }
620:
621: public function getSmallerType(PhpVersion $phpVersion): Type
622: {
623: return $this->resolve()->getSmallerType($phpVersion);
624: }
625:
626: public function getSmallerOrEqualType(PhpVersion $phpVersion): Type
627: {
628: return $this->resolve()->getSmallerOrEqualType($phpVersion);
629: }
630:
631: public function getGreaterType(PhpVersion $phpVersion): Type
632: {
633: return $this->resolve()->getGreaterType($phpVersion);
634: }
635:
636: public function getGreaterOrEqualType(PhpVersion $phpVersion): Type
637: {
638: return $this->resolve()->getGreaterOrEqualType($phpVersion);
639: }
640:
641: public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
642: {
643: return $this->resolve()->inferTemplateTypes($receivedType);
644: }
645:
646: public function tryRemove(Type $typeToRemove): ?Type
647: {
648: return $this->resolve()->tryRemove($typeToRemove);
649: }
650:
651: public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
652: {
653: $result = $this->resolve();
654:
655: if ($result instanceof CompoundType) {
656: return $result->isSubTypeOf($otherType);
657: }
658:
659: return $otherType->isSuperTypeOf($result);
660: }
661:
662: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
663: {
664: $result = $this->resolve();
665:
666: if ($result instanceof CompoundType) {
667: return $result->isAcceptedBy($acceptingType, $strictTypes);
668: }
669:
670: return $acceptingType->accepts($result, $strictTypes);
671: }
672:
673: public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
674: {
675: $result = $this->resolve();
676:
677: if ($result instanceof CompoundType) {
678: return $result->isGreaterThan($otherType, $phpVersion);
679: }
680:
681: return $otherType->isSmallerThan($result, $phpVersion);
682: }
683:
684: public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
685: {
686: $result = $this->resolve();
687:
688: if ($result instanceof CompoundType) {
689: return $result->isGreaterThanOrEqual($otherType, $phpVersion);
690: }
691:
692: return $otherType->isSmallerThanOrEqual($result, $phpVersion);
693: }
694:
695: public function exponentiate(Type $exponent): Type
696: {
697: return $this->resolve()->exponentiate($exponent);
698: }
699:
700: public function getFiniteTypes(): array
701: {
702: return $this->resolve()->getFiniteTypes();
703: }
704:
705: public function resolve(): Type
706: {
707: return $this->result ??= $this->getResult();
708: }
709:
710: abstract protected function getResult(): Type;
711:
712: public function toNativePhpTypeNode(NativeTypePosition $position)
713: {
714: return $this->resolve()->toNativePhpTypeNode($position);
715: }
716:
717: public function hasTemplateOrLateResolvableType(): bool
718: {
719: return true;
720: }
721:
722: }
723: