1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: use PHPStan\Php\PhpVersion;
6: use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
8: use PHPStan\Reflection\ClassConstantReflection;
9: use PHPStan\Reflection\ClassMemberAccessAnswerer;
10: use PHPStan\Reflection\ClassReflection;
11: use PHPStan\Reflection\ExtendedMethodReflection;
12: use PHPStan\Reflection\ExtendedPropertyReflection;
13: use PHPStan\Reflection\Type\CallbackUnresolvedMethodPrototypeReflection;
14: use PHPStan\Reflection\Type\CallbackUnresolvedPropertyPrototypeReflection;
15: use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection;
16: use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
17: use PHPStan\TrinaryLogic;
18: use PHPStan\Type\Generic\GenericObjectType;
19: use PHPStan\Type\Generic\TemplateTypeHelper;
20: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
21: use PHPStan\Type\Traits\NonGenericTypeTrait;
22: use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;
23: use function get_class;
24: use function sprintf;
25:
26: /** @api */
27: class StaticType implements TypeWithClassName, SubtractableType
28: {
29:
30: use NonGenericTypeTrait;
31: use UndecidedComparisonTypeTrait;
32: use NonGeneralizableTypeTrait;
33:
34: private ?Type $subtractedType;
35:
36: private ?ObjectType $staticObjectType = null;
37:
38: private string $baseClass;
39:
40: /**
41: * @api
42: */
43: public function __construct(
44: private ClassReflection $classReflection,
45: ?Type $subtractedType = null,
46: )
47: {
48: if ($subtractedType instanceof NeverType) {
49: $subtractedType = null;
50: }
51:
52: $this->subtractedType = $subtractedType;
53: $this->baseClass = $classReflection->getName();
54: }
55:
56: public function getClassName(): string
57: {
58: return $this->baseClass;
59: }
60:
61: public function getClassReflection(): ClassReflection
62: {
63: return $this->classReflection;
64: }
65:
66: public function getAncestorWithClassName(string $className): ?TypeWithClassName
67: {
68: $ancestor = $this->getStaticObjectType()->getAncestorWithClassName($className);
69: if ($ancestor === null) {
70: return null;
71: }
72:
73: $classReflection = $ancestor->getClassReflection();
74: if ($classReflection !== null) {
75: return $this->changeBaseClass($classReflection);
76: }
77:
78: return null;
79: }
80:
81: public function getStaticObjectType(): ObjectType
82: {
83: if ($this->staticObjectType === null) {
84: if ($this->classReflection->isGeneric()) {
85: $typeMap = $this->classReflection->getActiveTemplateTypeMap()->map(static fn (string $name, Type $type): Type => TemplateTypeHelper::toArgument($type));
86: $varianceMap = $this->classReflection->getCallSiteVarianceMap();
87: return $this->staticObjectType = new GenericObjectType(
88: $this->classReflection->getName(),
89: $this->classReflection->typeMapToList($typeMap),
90: $this->subtractedType,
91: variances: $this->classReflection->varianceMapToList($varianceMap),
92: );
93: }
94:
95: return $this->staticObjectType = new ObjectType($this->classReflection->getName(), $this->subtractedType, $this->classReflection);
96: }
97:
98: return $this->staticObjectType;
99: }
100:
101: public function getReferencedClasses(): array
102: {
103: return $this->getStaticObjectType()->getReferencedClasses();
104: }
105:
106: public function getObjectClassNames(): array
107: {
108: return $this->getStaticObjectType()->getObjectClassNames();
109: }
110:
111: public function getObjectClassReflections(): array
112: {
113: return $this->getStaticObjectType()->getObjectClassReflections();
114: }
115:
116: public function getArrays(): array
117: {
118: return $this->getStaticObjectType()->getArrays();
119: }
120:
121: public function getConstantArrays(): array
122: {
123: return $this->getStaticObjectType()->getConstantArrays();
124: }
125:
126: public function getConstantStrings(): array
127: {
128: return $this->getStaticObjectType()->getConstantStrings();
129: }
130:
131: public function accepts(Type $type, bool $strictTypes): AcceptsResult
132: {
133: if ($type instanceof CompoundType) {
134: return $type->isAcceptedBy($this, $strictTypes);
135: }
136:
137: if (!$type instanceof static) {
138: return AcceptsResult::createNo();
139: }
140:
141: return $this->getStaticObjectType()->accepts($type->getStaticObjectType(), $strictTypes);
142: }
143:
144: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
145: {
146: if ($type instanceof self) {
147: return $this->getStaticObjectType()->isSuperTypeOf($type);
148: }
149:
150: if ($type instanceof ObjectWithoutClassType) {
151: return IsSuperTypeOfResult::createMaybe();
152: }
153:
154: if ($type instanceof ObjectType) {
155: $result = $this->getStaticObjectType()->isSuperTypeOf($type);
156: if ($result->yes()) {
157: $classReflection = $type->getClassReflection();
158: if ($classReflection !== null && $classReflection->isFinal()) {
159: return $result;
160: }
161: }
162:
163: return $result->and(IsSuperTypeOfResult::createMaybe());
164: }
165:
166: if ($type instanceof CompoundType) {
167: return $type->isSubTypeOf($this);
168: }
169:
170: return IsSuperTypeOfResult::createNo();
171: }
172:
173: public function equals(Type $type): bool
174: {
175: if (get_class($type) !== static::class) {
176: return false;
177: }
178:
179: return $this->getStaticObjectType()->equals($type->getStaticObjectType());
180: }
181:
182: public function describe(VerbosityLevel $level): string
183: {
184: return sprintf('static(%s)', $this->getStaticObjectType()->describe($level));
185: }
186:
187: public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type
188: {
189: return $this->getStaticObjectType()->getTemplateType($ancestorClassName, $templateTypeName);
190: }
191:
192: public function isObject(): TrinaryLogic
193: {
194: return $this->getStaticObjectType()->isObject();
195: }
196:
197: public function isEnum(): TrinaryLogic
198: {
199: return $this->getStaticObjectType()->isEnum();
200: }
201:
202: public function canAccessProperties(): TrinaryLogic
203: {
204: return $this->getStaticObjectType()->canAccessProperties();
205: }
206:
207: public function hasProperty(string $propertyName): TrinaryLogic
208: {
209: return $this->getStaticObjectType()->hasProperty($propertyName);
210: }
211:
212: public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
213: {
214: return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty();
215: }
216:
217: public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection
218: {
219: $staticObject = $this->getStaticObjectType();
220: $nakedProperty = $staticObject->getUnresolvedPropertyPrototype($propertyName, $scope)->getNakedProperty();
221:
222: $ancestor = $this->getAncestorWithClassName($nakedProperty->getDeclaringClass()->getName());
223: $classReflection = null;
224: if ($ancestor !== null) {
225: $classReflection = $ancestor->getClassReflection();
226: }
227: if ($classReflection === null) {
228: $classReflection = $nakedProperty->getDeclaringClass();
229: }
230:
231: return new CallbackUnresolvedPropertyPrototypeReflection(
232: $nakedProperty,
233: $classReflection,
234: false,
235: fn (Type $type): Type => $this->transformStaticType($type, $scope),
236: );
237: }
238:
239: public function hasInstanceProperty(string $propertyName): TrinaryLogic
240: {
241: return $this->getStaticObjectType()->hasInstanceProperty($propertyName);
242: }
243:
244: public function getInstanceProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
245: {
246: return $this->getUnresolvedInstancePropertyPrototype($propertyName, $scope)->getTransformedProperty();
247: }
248:
249: public function getUnresolvedInstancePropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection
250: {
251: $staticObject = $this->getStaticObjectType();
252: $nakedProperty = $staticObject->getUnresolvedInstancePropertyPrototype($propertyName, $scope)->getNakedProperty();
253:
254: $ancestor = $this->getAncestorWithClassName($nakedProperty->getDeclaringClass()->getName());
255: $classReflection = null;
256: if ($ancestor !== null) {
257: $classReflection = $ancestor->getClassReflection();
258: }
259: if ($classReflection === null) {
260: $classReflection = $nakedProperty->getDeclaringClass();
261: }
262:
263: return new CallbackUnresolvedPropertyPrototypeReflection(
264: $nakedProperty,
265: $classReflection,
266: false,
267: fn (Type $type): Type => $this->transformStaticType($type, $scope),
268: );
269: }
270:
271: public function hasStaticProperty(string $propertyName): TrinaryLogic
272: {
273: return $this->getStaticObjectType()->hasStaticProperty($propertyName);
274: }
275:
276: public function getStaticProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
277: {
278: return $this->getUnresolvedStaticPropertyPrototype($propertyName, $scope)->getTransformedProperty();
279: }
280:
281: public function getUnresolvedStaticPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection
282: {
283: $staticObject = $this->getStaticObjectType();
284: $nakedProperty = $staticObject->getUnresolvedStaticPropertyPrototype($propertyName, $scope)->getNakedProperty();
285:
286: $ancestor = $this->getAncestorWithClassName($nakedProperty->getDeclaringClass()->getName());
287: $classReflection = null;
288: if ($ancestor !== null) {
289: $classReflection = $ancestor->getClassReflection();
290: }
291: if ($classReflection === null) {
292: $classReflection = $nakedProperty->getDeclaringClass();
293: }
294:
295: return new CallbackUnresolvedPropertyPrototypeReflection(
296: $nakedProperty,
297: $classReflection,
298: false,
299: fn (Type $type): Type => $this->transformStaticType($type, $scope),
300: );
301: }
302:
303: public function canCallMethods(): TrinaryLogic
304: {
305: return $this->getStaticObjectType()->canCallMethods();
306: }
307:
308: public function hasMethod(string $methodName): TrinaryLogic
309: {
310: return $this->getStaticObjectType()->hasMethod($methodName);
311: }
312:
313: public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): ExtendedMethodReflection
314: {
315: return $this->getUnresolvedMethodPrototype($methodName, $scope)->getTransformedMethod();
316: }
317:
318: public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection
319: {
320: $staticObject = $this->getStaticObjectType();
321: $nakedMethod = $staticObject->getUnresolvedMethodPrototype($methodName, $scope)->getNakedMethod();
322:
323: $ancestor = $this->getAncestorWithClassName($nakedMethod->getDeclaringClass()->getName());
324: $classReflection = null;
325: if ($ancestor !== null) {
326: $classReflection = $ancestor->getClassReflection();
327: }
328: if ($classReflection === null) {
329: $classReflection = $nakedMethod->getDeclaringClass();
330: }
331:
332: return new CallbackUnresolvedMethodPrototypeReflection(
333: $nakedMethod,
334: $classReflection,
335: false,
336: fn (Type $type): Type => $this->transformStaticType($type, $scope),
337: );
338: }
339:
340: private function transformStaticType(Type $type, ClassMemberAccessAnswerer $scope): Type
341: {
342: return TypeTraverser::map($type, function (Type $type, callable $traverse) use ($scope): Type {
343: if ($type instanceof StaticType) {
344: $classReflection = $this->classReflection;
345: $isFinal = false;
346: if ($scope->isInClass()) {
347: $classReflection = $scope->getClassReflection();
348: $isFinal = $classReflection->isFinal();
349: }
350: $type = $type->changeBaseClass($classReflection);
351: if (!$isFinal || $type instanceof ThisType) {
352: return $traverse($type);
353: }
354:
355: return $traverse($type->getStaticObjectType());
356: }
357:
358: return $traverse($type);
359: });
360: }
361:
362: public function canAccessConstants(): TrinaryLogic
363: {
364: return $this->getStaticObjectType()->canAccessConstants();
365: }
366:
367: public function hasConstant(string $constantName): TrinaryLogic
368: {
369: return $this->getStaticObjectType()->hasConstant($constantName);
370: }
371:
372: public function getConstant(string $constantName): ClassConstantReflection
373: {
374: return $this->getStaticObjectType()->getConstant($constantName);
375: }
376:
377: public function changeBaseClass(ClassReflection $classReflection): self
378: {
379: return new self($classReflection, $this->subtractedType);
380: }
381:
382: public function isIterable(): TrinaryLogic
383: {
384: return $this->getStaticObjectType()->isIterable();
385: }
386:
387: public function isIterableAtLeastOnce(): TrinaryLogic
388: {
389: return $this->getStaticObjectType()->isIterableAtLeastOnce();
390: }
391:
392: public function getArraySize(): Type
393: {
394: return $this->getStaticObjectType()->getArraySize();
395: }
396:
397: public function getIterableKeyType(): Type
398: {
399: return $this->getStaticObjectType()->getIterableKeyType();
400: }
401:
402: public function getFirstIterableKeyType(): Type
403: {
404: return $this->getStaticObjectType()->getFirstIterableKeyType();
405: }
406:
407: public function getLastIterableKeyType(): Type
408: {
409: return $this->getStaticObjectType()->getLastIterableKeyType();
410: }
411:
412: public function getIterableValueType(): Type
413: {
414: return $this->getStaticObjectType()->getIterableValueType();
415: }
416:
417: public function getFirstIterableValueType(): Type
418: {
419: return $this->getStaticObjectType()->getFirstIterableValueType();
420: }
421:
422: public function getLastIterableValueType(): Type
423: {
424: return $this->getStaticObjectType()->getLastIterableValueType();
425: }
426:
427: public function isOffsetAccessible(): TrinaryLogic
428: {
429: return $this->getStaticObjectType()->isOffsetAccessible();
430: }
431:
432: public function isOffsetAccessLegal(): TrinaryLogic
433: {
434: return $this->getStaticObjectType()->isOffsetAccessLegal();
435: }
436:
437: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
438: {
439: return $this->getStaticObjectType()->hasOffsetValueType($offsetType);
440: }
441:
442: public function getOffsetValueType(Type $offsetType): Type
443: {
444: return $this->getStaticObjectType()->getOffsetValueType($offsetType);
445: }
446:
447: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
448: {
449: return $this->getStaticObjectType()->setOffsetValueType($offsetType, $valueType, $unionValues);
450: }
451:
452: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
453: {
454: return $this->getStaticObjectType()->setExistingOffsetValueType($offsetType, $valueType);
455: }
456:
457: public function unsetOffset(Type $offsetType): Type
458: {
459: return $this->getStaticObjectType()->unsetOffset($offsetType);
460: }
461:
462: public function getKeysArrayFiltered(Type $filterValueType, TrinaryLogic $strict): Type
463: {
464: return $this->getStaticObjectType()->getKeysArrayFiltered($filterValueType, $strict);
465: }
466:
467: public function getKeysArray(): Type
468: {
469: return $this->getStaticObjectType()->getKeysArray();
470: }
471:
472: public function getValuesArray(): Type
473: {
474: return $this->getStaticObjectType()->getValuesArray();
475: }
476:
477: public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
478: {
479: return $this->getStaticObjectType()->chunkArray($lengthType, $preserveKeys);
480: }
481:
482: public function fillKeysArray(Type $valueType): Type
483: {
484: return $this->getStaticObjectType()->fillKeysArray($valueType);
485: }
486:
487: public function flipArray(): Type
488: {
489: return $this->getStaticObjectType()->flipArray();
490: }
491:
492: public function intersectKeyArray(Type $otherArraysType): Type
493: {
494: return $this->getStaticObjectType()->intersectKeyArray($otherArraysType);
495: }
496:
497: public function popArray(): Type
498: {
499: return $this->getStaticObjectType()->popArray();
500: }
501:
502: public function reverseArray(TrinaryLogic $preserveKeys): Type
503: {
504: return $this->getStaticObjectType()->reverseArray($preserveKeys);
505: }
506:
507: public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type
508: {
509: return $this->getStaticObjectType()->searchArray($needleType, $strict);
510: }
511:
512: public function shiftArray(): Type
513: {
514: return $this->getStaticObjectType()->shiftArray();
515: }
516:
517: public function shuffleArray(): Type
518: {
519: return $this->getStaticObjectType()->shuffleArray();
520: }
521:
522: public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type
523: {
524: return $this->getStaticObjectType()->sliceArray($offsetType, $lengthType, $preserveKeys);
525: }
526:
527: public function spliceArray(Type $offsetType, Type $lengthType, Type $replacementType): Type
528: {
529: return $this->getStaticObjectType()->spliceArray($offsetType, $lengthType, $replacementType);
530: }
531:
532: public function isCallable(): TrinaryLogic
533: {
534: return $this->getStaticObjectType()->isCallable();
535: }
536:
537: public function getEnumCases(): array
538: {
539: return $this->getStaticObjectType()->getEnumCases();
540: }
541:
542: public function isArray(): TrinaryLogic
543: {
544: return $this->getStaticObjectType()->isArray();
545: }
546:
547: public function isConstantArray(): TrinaryLogic
548: {
549: return $this->getStaticObjectType()->isConstantArray();
550: }
551:
552: public function isOversizedArray(): TrinaryLogic
553: {
554: return $this->getStaticObjectType()->isOversizedArray();
555: }
556:
557: public function isList(): TrinaryLogic
558: {
559: return $this->getStaticObjectType()->isList();
560: }
561:
562: public function isNull(): TrinaryLogic
563: {
564: return $this->getStaticObjectType()->isNull();
565: }
566:
567: public function isConstantValue(): TrinaryLogic
568: {
569: return $this->getStaticObjectType()->isConstantValue();
570: }
571:
572: public function isConstantScalarValue(): TrinaryLogic
573: {
574: return $this->getStaticObjectType()->isConstantScalarValue();
575: }
576:
577: public function getConstantScalarTypes(): array
578: {
579: return $this->getStaticObjectType()->getConstantScalarTypes();
580: }
581:
582: public function getConstantScalarValues(): array
583: {
584: return $this->getStaticObjectType()->getConstantScalarValues();
585: }
586:
587: public function isTrue(): TrinaryLogic
588: {
589: return $this->getStaticObjectType()->isTrue();
590: }
591:
592: public function isFalse(): TrinaryLogic
593: {
594: return $this->getStaticObjectType()->isFalse();
595: }
596:
597: public function isBoolean(): TrinaryLogic
598: {
599: return $this->getStaticObjectType()->isBoolean();
600: }
601:
602: public function isFloat(): TrinaryLogic
603: {
604: return $this->getStaticObjectType()->isFloat();
605: }
606:
607: public function isInteger(): TrinaryLogic
608: {
609: return $this->getStaticObjectType()->isInteger();
610: }
611:
612: public function isString(): TrinaryLogic
613: {
614: return $this->getStaticObjectType()->isString();
615: }
616:
617: public function isNumericString(): TrinaryLogic
618: {
619: return $this->getStaticObjectType()->isNumericString();
620: }
621:
622: public function isNonEmptyString(): TrinaryLogic
623: {
624: return $this->getStaticObjectType()->isNonEmptyString();
625: }
626:
627: public function isNonFalsyString(): TrinaryLogic
628: {
629: return $this->getStaticObjectType()->isNonFalsyString();
630: }
631:
632: public function isLiteralString(): TrinaryLogic
633: {
634: return $this->getStaticObjectType()->isLiteralString();
635: }
636:
637: public function isLowercaseString(): TrinaryLogic
638: {
639: return $this->getStaticObjectType()->isLowercaseString();
640: }
641:
642: public function isUppercaseString(): TrinaryLogic
643: {
644: return $this->getStaticObjectType()->isUppercaseString();
645: }
646:
647: public function isClassString(): TrinaryLogic
648: {
649: return $this->getStaticObjectType()->isClassString();
650: }
651:
652: public function getClassStringObjectType(): Type
653: {
654: return $this->getStaticObjectType()->getClassStringObjectType();
655: }
656:
657: public function getObjectTypeOrClassStringObjectType(): Type
658: {
659: return $this;
660: }
661:
662: public function isVoid(): TrinaryLogic
663: {
664: return $this->getStaticObjectType()->isVoid();
665: }
666:
667: public function isScalar(): TrinaryLogic
668: {
669: return $this->getStaticObjectType()->isScalar();
670: }
671:
672: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
673: {
674: return new BooleanType();
675: }
676:
677: public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array
678: {
679: return $this->getStaticObjectType()->getCallableParametersAcceptors($scope);
680: }
681:
682: public function isCloneable(): TrinaryLogic
683: {
684: return TrinaryLogic::createYes();
685: }
686:
687: public function toNumber(): Type
688: {
689: return new ErrorType();
690: }
691:
692: public function toAbsoluteNumber(): Type
693: {
694: return new ErrorType();
695: }
696:
697: public function toString(): Type
698: {
699: return $this->getStaticObjectType()->toString();
700: }
701:
702: public function toInteger(): Type
703: {
704: return new ErrorType();
705: }
706:
707: public function toFloat(): Type
708: {
709: return new ErrorType();
710: }
711:
712: public function toArray(): Type
713: {
714: return $this->getStaticObjectType()->toArray();
715: }
716:
717: public function toArrayKey(): Type
718: {
719: return $this->getStaticObjectType()->toArrayKey();
720: }
721:
722: public function toCoercedArgumentType(bool $strictTypes): Type
723: {
724: return $this->getStaticObjectType()->toCoercedArgumentType($strictTypes);
725: }
726:
727: public function toBoolean(): BooleanType
728: {
729: return $this->getStaticObjectType()->toBoolean();
730: }
731:
732: public function traverse(callable $cb): Type
733: {
734: $subtractedType = $this->subtractedType !== null ? $cb($this->subtractedType) : null;
735:
736: if ($subtractedType !== $this->subtractedType) {
737: return new self(
738: $this->classReflection,
739: $subtractedType,
740: );
741: }
742:
743: return $this;
744: }
745:
746: public function traverseSimultaneously(Type $right, callable $cb): Type
747: {
748: if ($this->subtractedType === null) {
749: return $this;
750: }
751:
752: return new self($this->classReflection);
753: }
754:
755: public function subtract(Type $type): Type
756: {
757: if ($this->subtractedType !== null) {
758: $type = TypeCombinator::union($this->subtractedType, $type);
759: }
760:
761: return $this->changeSubtractedType($type);
762: }
763:
764: public function getTypeWithoutSubtractedType(): Type
765: {
766: return $this->changeSubtractedType(null);
767: }
768:
769: public function changeSubtractedType(?Type $subtractedType): Type
770: {
771: if ($subtractedType !== null) {
772: $classReflection = $this->getClassReflection();
773: if ($classReflection->getAllowedSubTypes() !== null) {
774: $objectType = $this->getStaticObjectType()->changeSubtractedType($subtractedType);
775: if ($objectType instanceof NeverType) {
776: return $objectType;
777: }
778:
779: if ($objectType instanceof ObjectType && $objectType->getSubtractedType() !== null) {
780: return new self($classReflection, $objectType->getSubtractedType());
781: }
782:
783: return TypeCombinator::intersect($this, $objectType);
784: }
785: }
786:
787: return new self($this->classReflection, $subtractedType);
788: }
789:
790: public function getSubtractedType(): ?Type
791: {
792: return $this->subtractedType;
793: }
794:
795: public function tryRemove(Type $typeToRemove): ?Type
796: {
797: if ($this->getStaticObjectType()->isSuperTypeOf($typeToRemove)->yes()) {
798: return $this->subtract($typeToRemove);
799: }
800:
801: return null;
802: }
803:
804: public function exponentiate(Type $exponent): Type
805: {
806: return $this->getStaticObjectType()->exponentiate($exponent);
807: }
808:
809: public function getFiniteTypes(): array
810: {
811: return $this->getStaticObjectType()->getFiniteTypes();
812: }
813:
814: public function toPhpDocNode(): TypeNode
815: {
816: return new IdentifierTypeNode('static');
817: }
818:
819: }
820: