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\TrinaryLogic;
9: use PHPStan\Turbo\ShadowedByTurboExtension;
10: use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
11: use PHPStan\Type\Constant\ConstantArrayType;
12: use PHPStan\Type\Constant\ConstantBooleanType;
13: use PHPStan\Type\Constant\ConstantIntegerType;
14: use PHPStan\Type\Traits\NonArrayTypeTrait;
15: use PHPStan\Type\Traits\NonCallableTypeTrait;
16: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
17: use PHPStan\Type\Traits\NonGenericTypeTrait;
18: use PHPStan\Type\Traits\NonIterableTypeTrait;
19: use PHPStan\Type\Traits\NonObjectTypeTrait;
20: use PHPStan\Type\Traits\NonOffsetAccessibleTypeTrait;
21: use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
22: use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;
23:
24: /** @api */
25: #[ShadowedByTurboExtension(implementation: __DIR__ . '/../../turbo-ext/src/IntegerType.cpp')]
26: #[InstanceofDeprecated(insteadUse: 'Type::isInteger()')]
27: class IntegerType implements Type
28: {
29:
30: use JustNullableTypeTrait;
31: use NonArrayTypeTrait;
32: use NonCallableTypeTrait;
33: use NonIterableTypeTrait;
34: use NonObjectTypeTrait;
35: use UndecidedBooleanTypeTrait;
36: use UndecidedComparisonTypeTrait;
37: use NonGenericTypeTrait;
38: use NonOffsetAccessibleTypeTrait;
39: use NonGeneralizableTypeTrait;
40:
41: /** @api */
42: public function __construct()
43: {
44: }
45:
46: public function describe(VerbosityLevel $level): string
47: {
48: return 'int';
49: }
50:
51: public function getConstantStrings(): array
52: {
53: return [];
54: }
55:
56: public function toNumber(): Type
57: {
58: return $this;
59: }
60:
61: public function toBitwiseNotType(): Type
62: {
63: return new IntegerType();
64: }
65:
66: public function toAbsoluteNumber(): Type
67: {
68: return IntegerRangeType::createAllGreaterThanOrEqualTo(0);
69: }
70:
71: public function toFloat(): Type
72: {
73: return new FloatType();
74: }
75:
76: public function toInteger(): Type
77: {
78: return $this;
79: }
80:
81: public function toString(): Type
82: {
83: return new IntersectionType([
84: new StringType(),
85: new AccessoryDecimalIntegerStringType(),
86: ]);
87: }
88:
89: public function toArray(): Type
90: {
91: return new ConstantArrayType(
92: [new ConstantIntegerType(0)],
93: [$this],
94: [1],
95: isList: TrinaryLogic::createYes(),
96: );
97: }
98:
99: public function toArrayKey(): Type
100: {
101: return $this;
102: }
103:
104: public function toCoercedArgumentType(bool $strictTypes): Type
105: {
106: if (!$strictTypes) {
107: return TypeCombinator::union($this, $this->toFloat(), $this->toString(), $this->toBoolean());
108: }
109:
110: return TypeCombinator::union($this, $this->toFloat());
111: }
112:
113: public function isOffsetAccessLegal(): TrinaryLogic
114: {
115: return TrinaryLogic::createYes();
116: }
117:
118: public function isNull(): TrinaryLogic
119: {
120: return TrinaryLogic::createNo();
121: }
122:
123: public function isTrue(): TrinaryLogic
124: {
125: return TrinaryLogic::createNo();
126: }
127:
128: public function isFalse(): TrinaryLogic
129: {
130: return TrinaryLogic::createNo();
131: }
132:
133: public function isBoolean(): TrinaryLogic
134: {
135: return TrinaryLogic::createNo();
136: }
137:
138: public function isFloat(): TrinaryLogic
139: {
140: return TrinaryLogic::createNo();
141: }
142:
143: public function isInteger(): TrinaryLogic
144: {
145: return TrinaryLogic::createYes();
146: }
147:
148: public function isScalar(): TrinaryLogic
149: {
150: return TrinaryLogic::createYes();
151: }
152:
153: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
154: {
155: if ($type->isArray()->yes()) {
156: return new ConstantBooleanType(false);
157: }
158:
159: if (
160: $phpVersion->nonNumericStringAndIntegerIsFalseOnLooseComparison()
161: && $type->isString()->yes()
162: && $type->isNumericString()->no()
163: ) {
164: return new ConstantBooleanType(false);
165: }
166:
167: return new BooleanType();
168: }
169:
170: public function tryRemove(Type $typeToRemove): ?Type
171: {
172: if ($typeToRemove instanceof IntegerRangeType || $typeToRemove instanceof ConstantIntegerType) {
173: if ($typeToRemove instanceof IntegerRangeType) {
174: $removeValueMin = $typeToRemove->getMin();
175: $removeValueMax = $typeToRemove->getMax();
176: } else {
177: $removeValueMin = $typeToRemove->getValue();
178: $removeValueMax = $typeToRemove->getValue();
179: }
180: $lowerPart = $removeValueMin !== null ? IntegerRangeType::fromInterval(null, $removeValueMin, -1) : null;
181: $upperPart = $removeValueMax !== null ? IntegerRangeType::fromInterval($removeValueMax, null, +1) : null;
182: if ($lowerPart !== null && $upperPart !== null) {
183: return new UnionType([$lowerPart, $upperPart]);
184: }
185: return $lowerPart ?? $upperPart ?? new NeverType();
186: }
187:
188: return null;
189: }
190:
191: public function getFiniteTypes(): array
192: {
193: return [];
194: }
195:
196: public function exponentiate(Type $exponent): Type
197: {
198: return ExponentiateHelper::exponentiate($this, $exponent);
199: }
200:
201: public function toPhpDocNode(): TypeNode
202: {
203: return new IdentifierTypeNode('int');
204: }
205:
206: public function hasTemplateOrLateResolvableType(): bool
207: {
208: return false;
209: }
210:
211: }
212: