diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index aac86ee18..efd902c28 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -1129,14 +1129,14 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic public function getOffsetValueType(Type $offsetType): Type { - if (!$this->isExtraOffsetAccessibleClass()->no()) { - return new MixedType(); - } - if ($this->isInstanceOf(ArrayAccess::class)->yes()) { return RecursionGuard::run($this, fn (): Type => ParametersAcceptorSelector::selectSingle($this->getMethod('offsetGet', new OutOfClassScope())->getVariants())->getReturnType()); } + if (!$this->isExtraOffsetAccessibleClass()->no()) { + return new MixedType(); + } + return new ErrorType(); } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 0a9424b19..7b11ad16c 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1433,6 +1433,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9123.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10037.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/set-type-type-specifying.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9456.php'); } /** diff --git a/tests/PHPStan/Analyser/data/bug-9456.php b/tests/PHPStan/Analyser/data/bug-9456.php new file mode 100644 index 000000000..2d6b77821 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-9456.php @@ -0,0 +1,67 @@ + + */ +class Collection implements ArrayAccess { + /** + * @param (callable(TValue, TKey): bool)|TValue|string $key + * @param TValue|string|null $operator + * @param TValue|null $value + * @return static, static> + */ + public function partition($key, $operator = null, $value = null) {} // @phpstan-ignore-line + + /** + * @param TKey $key + * @return TValue + */ + public function offsetGet($key): mixed { return null; } // @phpstan-ignore-line + + /** + * @param TKey $key + * @return bool + */ + public function offsetExists($key): bool { return true; } + + /** + * @param TKey|null $key + * @param TValue $value + * @return void + */ + public function offsetSet($key, $value): void {} + + /** + * @param TKey $key + * @return void + */ + public function offsetUnset($key): void {} + + /** + * @param Collection $collection + */ + public function sayHello(Collection $collection): void + { + $result = $collection->partition('key'); + + assertType( + 'Bug9456\Collection, Bug9456\Collection>', + $result + ); + assertType('Bug9456\Collection', $result[0]); + assertType('Bug9456\Collection', $result[1]); + + [$one, $two] = $collection->partition('key'); + + assertType('Bug9456\Collection', $one); + assertType('Bug9456\Collection', $two); + } +} diff --git a/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php index 3221658bc..5536341f9 100644 --- a/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php @@ -168,4 +168,10 @@ public function testRuleWithNullsafeVariant(): void ]); } + + public function testRuleWithSimpleXml(): void + { + $this->analyse([__DIR__ . '/data/bug-9456-xml.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Operators/data/bug-9456-xml.php b/tests/PHPStan/Rules/Operators/data/bug-9456-xml.php new file mode 100644 index 000000000..6432a3a77 --- /dev/null +++ b/tests/PHPStan/Rules/Operators/data/bug-9456-xml.php @@ -0,0 +1,19 @@ +modules)) { + foreach ($xml->modules->module as $data) { + /** @var SimpleXMLElement $data */ + $attributes = $data->attributes(); + $install = ($attributes['install'] == 1) ? true : false; + } + } +}