diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index af6302edfc..58f87e93dc 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -34,6 +34,7 @@ use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Accessory\AccessoryUppercaseStringType; +use PHPStan\Type\Accessory\HasOffsetValueType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\BenevolentUnionType; @@ -1078,6 +1079,16 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback): TypeCombinator::union($leftType->getIterableValueType(), $rightType->getIterableValueType()), ); + foreach ($leftType->getConstantArrays() as $type) { + foreach ($type->getKeyTypes() as $i => $offsetType) { + if ($type->isOptionalKey($i)) { + continue; + } + $valueType = $type->getValueTypes()[$i]; + $arrayType = TypeCombinator::intersect($arrayType, new HasOffsetValueType($offsetType, $valueType)); + } + } + if ($leftType->isIterableAtLeastOnce()->yes() || $rightType->isIterableAtLeastOnce()->yes()) { $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); } diff --git a/tests/PHPStan/Analyser/nsrt/bug-11912.php b/tests/PHPStan/Analyser/nsrt/bug-11912.php new file mode 100644 index 0000000000..69d65ee01c --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11912.php @@ -0,0 +1,14 @@ + $results + * @param list $names + */ +function appendResults(array $results, array $names): bool { + // Make sure 'names' comes first in array + $results = ['names' => $names] + $results; + \PHPStan\Testing\assertType("list", $results['names']); + return true; +}