From 600e9e169eaad938f93ee1fddf4c6a5fde3c595e Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Tue, 18 Oct 2022 14:41:53 +0200 Subject: [PATCH] Fix issue #8087 --- src/Type/ArrayType.php | 36 +++++++++++-------- .../Analyser/NodeScopeResolverTest.php | 2 ++ tests/PHPStan/Analyser/data/bug-8087.php | 27 ++++++++++++++ 3 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 tests/PHPStan/Analyser/data/bug-8087.php diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index dd408dd9e3..c5815f7726 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -275,24 +275,30 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni $offsetType = self::castToArrayKeyType($offsetType); } - if ( - ($offsetType instanceof ConstantStringType || $offsetType instanceof ConstantIntegerType) - && $offsetType->isSuperTypeOf($this->keyType)->yes() - ) { - $builder = ConstantArrayTypeBuilder::createEmpty(); - $builder->setOffsetValueType($offsetType, $valueType); - return $builder->getArray(); - } + if ($offsetType instanceof ConstantStringType || $offsetType instanceof ConstantIntegerType) { + if ($offsetType->isSuperTypeOf($this->keyType)->yes()) { + $builder = ConstantArrayTypeBuilder::createEmpty(); + $builder->setOffsetValueType($offsetType, $valueType); + return $builder->getArray(); + } - $array = new self( - TypeCombinator::union($this->keyType, $offsetType), - $unionValues ? TypeCombinator::union($this->itemType, $valueType) : $valueType, - ); - if ($offsetType instanceof ConstantIntegerType || $offsetType instanceof ConstantStringType) { - return TypeCombinator::intersect($array, new HasOffsetValueType($offsetType, $valueType), new NonEmptyArrayType()); + return TypeCombinator::intersect( + new self( + TypeCombinator::union($this->keyType, $offsetType), + TypeCombinator::union($this->itemType, $valueType), + ), + new HasOffsetValueType($offsetType, $valueType), + new NonEmptyArrayType(), + ); } - return TypeCombinator::intersect($array, new NonEmptyArrayType()); + return TypeCombinator::intersect( + new self( + TypeCombinator::union($this->keyType, $offsetType), + $unionValues ? TypeCombinator::union($this->itemType, $valueType) : $valueType, + ), + new NonEmptyArrayType(), + ); } public function unsetOffset(Type $offsetType): Type diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index e6e8ef8ee9..22095c8e15 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1059,6 +1059,8 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8008.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5552.php'); yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Properties/data/bug-7839.php'); + + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8087.php'); } /** diff --git a/tests/PHPStan/Analyser/data/bug-8087.php b/tests/PHPStan/Analyser/data/bug-8087.php new file mode 100644 index 0000000000..1dc74349ea --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-8087.php @@ -0,0 +1,27 @@ + $data + **/ + public function sayHello(array $data): bool + { + \PHPStan\dumpType($data); + assertType('array', $data); + + $data['uses'] = ['']; + + assertType("non-empty-array&hasOffsetValue('uses', array{''})", $data); + + $data['uses'][] = ''; + + assertType("non-empty-array&hasOffsetValue('uses', array{'', ''})", $data); + + return count($data['foo']) > 0; + } +}