ArrayIterator's template is inferred from its constructor argumentnew ArrayIterator([1, 2, 3]) is ArrayIterator<int, int> with no
annotation at the call site. current() and key() return null at an
invalid position, so the receivers are nullable: the probe is the element
type, not the null.
generics_iterator_to_array consumes a declared iterator instead, so the
two rows separate the inference from the function signature.
Source: carthage-software/mago#2476 (1.57.0).
References:
- mago#2476| Analyzer | Version | Result | Diagnostics |
|---|---|---|---|
| phan | 6.0.11Phan 6.0.11 php-ast version 1.1.3 PHP version used to run Phan: 8.5.11 | Fail | No diagnostics reported. Expectation diffLine 35: Expected 1 error(s) Line 43: Expected 1 error(s) |
| phpstan | 2.3.5PHPStan - PHP Static Analysis Tool 2.3.5 | Pass reported Lv.5+ | generics_array_iterator_constructor_inference.php:35: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects string|null, int given. [reported-from-level=5] generics_array_iterator_constructor_inference.php:43: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, string given. [reported-from-level=5] With strict-rulesgenerics_array_iterator_constructor_inference.php:35: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects string|null, int given. generics_array_iterator_constructor_inference.php:43: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, string given. |
| psalm | 6.20.9Psalm 6.20.9@f67170ac3c3b931f5088681e21d6c8babc601c08 next: 7.0.4 |
Pass | generics_array_iterator_constructor_inference.php:35: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects null|string, but 1|2|3|null provided [InvalidScalarArgument] generics_array_iterator_constructor_inference.php:43: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, but 'a'|'b'|null provided [InvalidScalarArgument] |
| mago | 1.59.0mago 1.59.0 | Pass | generics_array_iterator_constructor_inference.php:35: Possible argument type mismatch for argument #1 of `Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString`: expected `null|string`, but possibly received `int|null`. [possibly-invalid-argument] generics_array_iterator_constructor_inference.php:43: Possible argument type mismatch for argument #1 of `Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt`: expected `int|null`, but possibly received `null|string`. [possibly-invalid-argument] |
| mir | 0.91.0mir 0.91.0 | Pass | generics_array_iterator_constructor_inference.php:35: InvalidArgument: Argument $value of takesNullableString() expects 'string|null', got 'int' [MIR0201] generics_array_iterator_constructor_inference.php:43: InvalidArgument: Argument $value of takesNullableInt() expects 'int|null', got 'string' [MIR0201] |
| phpantom | 0.11.1phpantom_lsp 0.11.1 | Pass | generics_array_iterator_constructor_inference.php:35: Argument 1 ($value) expects ?string, got int [type_mismatch_argument] generics_array_iterator_constructor_inference.php:43: Argument 1 ($value) expects ?int, got string [type_mismatch_argument] |
| intelephense | 1.18.5intelephense 1.18.5 | Fail | generics_array_iterator_constructor_inference.php:34: Expected type 'null|int'. Found 'mixed'. [P1006] generics_array_iterator_constructor_inference.php:35: Expected type 'null|string'. Found 'mixed'. [P1006] generics_array_iterator_constructor_inference.php:36: Expected type 'null|int'. Found 'string|int|null'. [P1006] generics_array_iterator_constructor_inference.php:42: Expected type 'null|string'. Found 'mixed'. [P1006] generics_array_iterator_constructor_inference.php:43: Expected type 'null|int'. Found 'mixed'. [P1006] Expectation diffLine 34: Expected valid value to be accepted, got ["Expected type 'null|int'. Found 'mixed'. [P1006]"] Line 36: Expected valid value to be accepted, got ["Expected type 'null|int'. Found 'string|int|null'. [P1006]"] Line 42: Expected valid value to be accepted, got ["Expected type 'null|string'. Found 'mixed'. [P1006]"] |
| phpactor | 2026.10.07.0Phpactor 2026.10.07.0 | Fail | No diagnostics reported. Expectation diffLine 35: Expected 1 error(s) Line 43: Expected 1 error(s) |
| phpy | 1.0.19490phpy 1.0.19490 | Fail | No diagnostics reported. Expectation diffLine 35: Expected 1 error(s) Line 43: Expected 1 error(s) |
| qodana | 262.11879.104PhpStorm 262.11879.104 | Fail | No diagnostics reported. Expectation diffLine 35: Expected 1 error(s) Line 43: Expected 1 error(s) |
| noverify | 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 | Fail | No diagnostics reported. Expectation diffLine 35: Expected 1 error(s) Line 43: Expected 1 error(s) |
| steins | 0.1.8steins 0.1.8 (2026-09-21 revision 76306a9) | Fail | No diagnostics reported. Expectation diffLine 35: Expected 1 error(s) Line 43: Expected 1 error(s) |
| phpstan-strict | 2.3.5PHPStan - PHP Static Analysis Tool 2.3.5 | Pass | generics_array_iterator_constructor_inference.php:35: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects string|null, int given. generics_array_iterator_constructor_inference.php:43: Parameter #1 $value of function Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, string given. |
| psalm-next | 7.0.4Psalm 7.0.4@fa5b1f6e665cb743838ffd865b8fc96207f9409f | Pass | generics_array_iterator_constructor_inference.php:35: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableString expects null|string, but 1|2|3|null provided [InvalidScalarArgument] generics_array_iterator_constructor_inference.php:43: Argument 1 of Conformance\Tests\GenericsArrayIteratorConstructorInference\takesNullableInt expects int|null, but 'a'|'b'|null provided [InvalidScalarArgument] |
<?php
declare(strict_types=1);
namespace Conformance\Tests\GenericsArrayIteratorConstructorInference;
/**
* `ArrayIterator`'s template is inferred from its constructor argument.
*
* `new ArrayIterator([1, 2, 3])` is `ArrayIterator<int, int>` with no
* annotation at the call site. `current()` and `key()` return null at an
* invalid position, so the receivers are nullable: the probe is the element
* type, not the null.
* `generics_iterator_to_array` consumes a declared iterator instead, so the
* two rows separate the inference from the function signature.
*
* Source: carthage-software/mago#2476 (1.57.0).
*
* References:
* - https://github.com/carthage-software/mago/pull/2476
*/
function takesNullableInt(?int $value): void
{
}
function takesNullableString(?string $value): void
{
}
function fromIntList(): void
{
$iterator = new \ArrayIterator([1, 2, 3]);
takesNullableInt($iterator->current()); // V
takesNullableString($iterator->current()); // E: current() is int|null
takesNullableInt($iterator->key()); // V: list keys are int
}
function fromStringList(): void
{
$iterator = new \ArrayIterator(['a', 'b']);
takesNullableString($iterator->current()); // V
takesNullableInt($iterator->current()); // E: current() is string|null
}