From 7a7b3863f91f241d5814eaa073278c2daf1fdde3 Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Fri, 4 Nov 2022 21:07:40 +0100 Subject: [PATCH] Fix array and iterable type action methods on `NeverType` --- src/Type/NeverType.php | 104 +++++++++++++++++- .../Analyser/NodeScopeResolverTest.php | 1 + ...isonOperatorsConstantConditionRuleTest.php | 5 + .../Rules/Comparison/data/bug-8277.php | 36 ++++++ 4 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 tests/PHPStan/Rules/Comparison/data/bug-8277.php diff --git a/src/Type/NeverType.php b/src/Type/NeverType.php index 90f64ea321..b353b00587 100644 --- a/src/Type/NeverType.php +++ b/src/Type/NeverType.php @@ -12,10 +12,8 @@ use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; -use PHPStan\Type\Traits\NonArrayTypeTrait; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; use PHPStan\Type\Traits\NonGenericTypeTrait; -use PHPStan\Type\Traits\NonIterableTypeTrait; use PHPStan\Type\Traits\NonRemoveableTypeTrait; use PHPStan\Type\Traits\UndecidedBooleanTypeTrait; use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait; @@ -25,9 +23,7 @@ class NeverType implements CompoundType { use UndecidedBooleanTypeTrait; - use NonArrayTypeTrait; use NonGenericTypeTrait; - use NonIterableTypeTrait; use UndecidedComparisonCompoundTypeTrait; use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; @@ -50,6 +46,16 @@ public function getReferencedClasses(): array return []; } + public function getArrays(): array + { + return []; + } + + public function getConstantArrays(): array + { + return []; + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { return TrinaryLogic::createYes(); @@ -149,16 +155,61 @@ public function isIterableAtLeastOnce(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function getArraySize(): Type + { + return new NeverType(); + } + public function getIterableKeyType(): Type { return new NeverType(); } + public function getFirstIterableKeyType(): Type + { + return new NeverType(); + } + + public function getLastIterableKeyType(): Type + { + return new NeverType(); + } + public function getIterableValueType(): Type { return new NeverType(); } + public function getFirstIterableValueType(): Type + { + return new NeverType(); + } + + public function getLastIterableValueType(): Type + { + return new NeverType(); + } + + public function isArray(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + + public function isConstantArray(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + + public function isOversizedArray(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + + public function isList(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function isOffsetAccessible(): TrinaryLogic { return TrinaryLogic::createYes(); @@ -184,6 +235,51 @@ public function unsetOffset(Type $offsetType): Type return new NeverType(); } + public function getKeysArray(): Type + { + return new NeverType(); + } + + public function getValuesArray(): Type + { + return new NeverType(); + } + + public function fillKeysArray(Type $valueType): Type + { + return new NeverType(); + } + + public function flipArray(): Type + { + return new NeverType(); + } + + public function intersectKeyArray(Type $otherArraysType): Type + { + return new NeverType(); + } + + public function popArray(): Type + { + return new NeverType(); + } + + public function searchArray(Type $needleType): Type + { + return new NeverType(); + } + + public function shiftArray(): Type + { + return new NeverType(); + } + + public function shuffleArray(): Type + { + return new NeverType(); + } + public function isCallable(): TrinaryLogic { return TrinaryLogic::createYes(); diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 2bb0bc8af1..a827d06f3b 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1122,6 +1122,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7913.php'); yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Functions/data/bug-8280.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8272.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Comparison/data/bug-8277.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/strtr.php'); } diff --git a/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php index 4f7448cd51..d9c59327b1 100644 --- a/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php @@ -17,6 +17,11 @@ protected function getRule(): Rule return new NumberComparisonOperatorsConstantConditionRule(); } + public function testBug8277(): void + { + $this->analyse([__DIR__ . '/data/bug-8277.php'], []); + } + public function testRule(): void { $this->analyse([__DIR__ . '/data/number-comparison-operators.php'], [ diff --git a/tests/PHPStan/Rules/Comparison/data/bug-8277.php b/tests/PHPStan/Rules/Comparison/data/bug-8277.php new file mode 100644 index 0000000000..3be373d818 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-8277.php @@ -0,0 +1,36 @@ + $stream + * @param positive-int $width + * + * @return Generator + */ +function swindow(iterable $stream, int $width): Generator +{ + $window = []; + foreach ($stream as $value) { + $window[] = $value; + $count = count($window); + + assertType('int<1, max>', $count); + + switch (true) { + case $count > $width: + array_shift($window); + // no break + case $count === $width: + yield $window; + } + } +}