1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Constant;
4:
5: use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
6: use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
8: use PHPStan\Type\CompoundType;
9: use PHPStan\Type\ConstantScalarType;
10: use PHPStan\Type\GeneralizePrecision;
11: use PHPStan\Type\IntegerRangeType;
12: use PHPStan\Type\IntegerType;
13: use PHPStan\Type\IsSuperTypeOfResult;
14: use PHPStan\Type\Traits\ConstantNumericComparisonTypeTrait;
15: use PHPStan\Type\Traits\ConstantScalarTypeTrait;
16: use PHPStan\Type\Type;
17: use PHPStan\Type\TypeCombinator;
18: use PHPStan\Type\VerbosityLevel;
19: use function abs;
20: use function sprintf;
21:
22: /** @api */
23: class ConstantIntegerType extends IntegerType implements ConstantScalarType
24: {
25:
26: use ConstantScalarTypeTrait;
27: use ConstantScalarToBooleanTrait;
28: use ConstantNumericComparisonTypeTrait;
29:
30: /** @api */
31: public function __construct(private int $value)
32: {
33: parent::__construct();
34: }
35:
36: public function getValue(): int
37: {
38: return $this->value;
39: }
40:
41: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
42: {
43: if ($type instanceof self) {
44: return $this->value === $type->value ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createNo();
45: }
46:
47: if ($type instanceof IntegerRangeType) {
48: $min = $type->getMin();
49: $max = $type->getMax();
50: if (($min === null || $min <= $this->value) && ($max === null || $this->value <= $max)) {
51: return IsSuperTypeOfResult::createMaybe();
52: }
53:
54: return IsSuperTypeOfResult::createNo();
55: }
56:
57: if ($type instanceof parent) {
58: return IsSuperTypeOfResult::createMaybe();
59: }
60:
61: if ($type instanceof CompoundType) {
62: return $type->isSubTypeOf($this);
63: }
64:
65: return IsSuperTypeOfResult::createNo();
66: }
67:
68: public function describe(VerbosityLevel $level): string
69: {
70: return $level->handle(
71: static fn (): string => 'int',
72: fn (): string => sprintf('%s', $this->value),
73: );
74: }
75:
76: public function toFloat(): Type
77: {
78: return new ConstantFloatType($this->value);
79: }
80:
81: public function toAbsoluteNumber(): Type
82: {
83: return new self(abs($this->value));
84: }
85:
86: public function toString(): Type
87: {
88: return new ConstantStringType((string) $this->value);
89: }
90:
91: public function toArrayKey(): Type
92: {
93: return $this;
94: }
95:
96: public function toCoercedArgumentType(bool $strictTypes): Type
97: {
98: if (!$strictTypes) {
99: return TypeCombinator::union($this, $this->toFloat(), $this->toString(), $this->toBoolean());
100: }
101:
102: return TypeCombinator::union($this, $this->toFloat());
103: }
104:
105: public function generalize(GeneralizePrecision $precision): Type
106: {
107: return new IntegerType();
108: }
109:
110: /**
111: * @return ConstTypeNode
112: */
113: public function toPhpDocNode(): TypeNode
114: {
115: return new ConstTypeNode(new ConstExprIntegerNode((string) $this->value));
116: }
117:
118: }
119: