diff --git a/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php b/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php index c440526fe..122bc65d7 100644 --- a/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php +++ b/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php @@ -49,6 +49,19 @@ final class ArrayTypeComparator return true; } + if ($container_type_part instanceof TKeyedArray + && $input_type_part instanceof TArray + && !$container_type_part->is_list + && !$container_type_part->isNonEmpty() + && !$container_type_part->isSealed() + && $input_type_part->equals( + $container_type_part->getGenericArrayType($container_type_part->isNonEmpty()), + false, + ) + ) { + return true; + } + if ($container_type_part instanceof TKeyedArray && $input_type_part instanceof TArray ) { diff --git a/tests/CallableTest.php b/tests/CallableTest.php index 23054bf9a..fc8c36d21 100644 --- a/tests/CallableTest.php +++ b/tests/CallableTest.php @@ -1892,6 +1892,22 @@ class CallableTest extends TestCase return [1, 2, 3]; });', ], + 'unsealedAllOptionalCbParam' => [ + 'code' => ') $arg + * @return void + */ + function foo($arg) {} + + /** + * @param array{a?: string}&array $cb_arg + * @return void + */ + function bar($cb_arg) {} + + foo("bar");', + ], ]; }