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