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