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