|
| 1 | +<?php // lint >= 8.6 |
| 2 | + |
| 3 | +declare(strict_types = 1); |
| 4 | + |
| 5 | +namespace Clamp; |
| 6 | + |
| 7 | +use DateTime; |
| 8 | +use DateTimeImmutable; |
| 9 | +use function PHPStan\Testing\assertType; |
| 10 | + |
| 11 | +/** @phpstan-impure */ |
| 12 | +function impureInt(): int |
| 13 | +{ |
| 14 | + return rand(0, 100) - 50; |
| 15 | +} |
| 16 | + |
| 17 | +/** |
| 18 | + * @param int<0, 100> $percent |
| 19 | + * @param int<-50, 50> $delta |
| 20 | + * @param list<int> $list |
| 21 | + */ |
| 22 | +function doFoo(int $i, float $f, int|float $n, int $a, int $b, string $s, ?int $maybe, int $percent, int $delta, array $list): void |
| 23 | +{ |
| 24 | + assertType('int<1, 10>', clamp($i, 1, 10)); |
| 25 | + assertType('float', clamp($f, 1.0, 10.0)); |
| 26 | + assertType('1.0|10.0|int<1, 10>', clamp($i, 1.0, 10.0)); |
| 27 | + assertType('float|int<0, 1>', clamp($n, 0, 1)); |
| 28 | + assertType('int', clamp($i, $a, $b)); |
| 29 | + assertType('int<0, 100>', clamp($percent + $delta, 0, 100)); |
| 30 | + assertType('5', clamp(5, 1, 10)); |
| 31 | + assertType('10', clamp(15, 1, 10)); |
| 32 | + assertType('1', clamp(-3, 1, 10)); |
| 33 | + assertType('string', clamp($s, 'a', 'm')); |
| 34 | + assertType('int<1, 10>', clamp($maybe, 1, 10)); |
| 35 | + assertType('int<1, 10>', clamp(max: 10, value: $i, min: 1)); |
| 36 | + assertType('int<1, 10>', clamp(impureInt(), 1, 10)); |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * @param 1|2|3 $lowUnion |
| 41 | + * @param 8|9|10 $highUnion |
| 42 | + * @param int<0, 5> $lowRange |
| 43 | + * @param int<8, 10> $highRange |
| 44 | + */ |
| 45 | +function doBounds(int $i, int $lowUnion, int $highUnion, int $lowRange, int $highRange): void |
| 46 | +{ |
| 47 | + assertType('int<1, 10>', clamp($i, $lowUnion, $highUnion)); |
| 48 | + assertType('5', clamp(5, $lowUnion, $highUnion)); |
| 49 | + assertType('1|2|3', clamp(0, $lowUnion, $highUnion)); |
| 50 | + assertType('int<0, 10>', clamp($i, $lowRange, $highRange)); |
| 51 | + assertType('int<8, 10>', clamp(12, $lowRange, $highRange)); |
| 52 | + assertType('int<0, 5>', clamp(-1, $lowRange, $highRange)); |
| 53 | +} |
| 54 | + |
| 55 | +/** |
| 56 | + * @param int|array<int> $intOrArray |
| 57 | + * @param list<int> $list |
| 58 | + */ |
| 59 | +function doArrays(int|array $intOrArray, array $list): void |
| 60 | +{ |
| 61 | + assertType('array<int>|int<1, 10>', clamp($intOrArray, 1, 10)); |
| 62 | + assertType('list<int>', clamp($list, [0], [10])); |
| 63 | + assertType('array{10}|array{1}|array{5}', clamp([5], [1], [10])); |
| 64 | + assertType('1|10|array{5}', clamp([5], 1, 10)); |
| 65 | +} |
| 66 | + |
| 67 | +function doDates(DateTimeImmutable $date, DateTimeImmutable $min, DateTimeImmutable $max, DateTime $mutable): void |
| 68 | +{ |
| 69 | + assertType('DateTimeImmutable', clamp($date, $min, $max)); |
| 70 | + assertType('DateTime|DateTimeImmutable', clamp($mutable, $min, $max)); |
| 71 | + assertType('DateTimeImmutable', clamp(new DateTimeImmutable('2025-08-01'), new DateTimeImmutable('2025-08-15'), new DateTimeImmutable('2025-08-31'))); |
| 72 | +} |
| 73 | + |
| 74 | +/** |
| 75 | + * @param array{int, 1, 10} $tuple |
| 76 | + * @param array{1, 10} $bounds |
| 77 | + * @param list<int> $list |
| 78 | + */ |
| 79 | +function doSplat(int $i, array $tuple, array $bounds, array $list): void |
| 80 | +{ |
| 81 | + assertType('mixed', clamp(...$tuple)); |
| 82 | + assertType('mixed', clamp($i, ...$bounds)); |
| 83 | + assertType('mixed', clamp(...$list)); |
| 84 | + assertType('mixed', clamp(...[$i], ...[1], ...[10])); |
| 85 | + assertType('mixed', clamp($i, 1, ...[10])); |
| 86 | +} |
0 commit comments