diff --git a/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php b/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php index 19b01cc7b..38c324a6a 100644 --- a/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php +++ b/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php @@ -158,7 +158,7 @@ class ArrayFetchChecker $const_array_key_type = $array_type->getGenericKeyType(); } - if ($dim_var_id && !$const_array_key_type->isMixed()) { + if ($dim_var_id && !$const_array_key_type->isMixed() && !$stmt->dim->inferredType->isMixed()) { $new_offset_type = clone $stmt->dim->inferredType; $const_array_key_atomic_types = $const_array_key_type->getTypes(); $project_checker = $statements_checker->getFileChecker()->project_checker; @@ -186,7 +186,11 @@ class ArrayFetchChecker )) { $new_offset_type->removeType($offset_key); } - } else { + } elseif (!TypeChecker::isContainedBy( + $project_checker->codebase, + $const_array_key_type, + new Type\Union([$offset_atomic_type]) + )) { $new_offset_type->removeType($offset_key); } } diff --git a/tests/ConstantTest.php b/tests/ConstantTest.php index 9f704aa5f..7fc5952bd 100644 --- a/tests/ConstantTest.php +++ b/tests/ConstantTest.php @@ -151,6 +151,46 @@ class ConstantTest extends TestCase } }', ], + 'noExceptionsOnMixedArrayKey' => [ + ' A::class, + "type2" => B::class, + ]; + + public function bar(array $data): void + { + if (!isset(self::TYPES[$data["type"]])) { + throw new \InvalidArgumentException("Unknown type"); + } + + $class = self::TYPES[$data["type"]]; + + $ret = finder($data["id"]); + + if (!$ret || !$ret instanceof $class) { + throw new \InvalidArgumentException; + } + } + }', + 'assertions' => [], + 'error_levels' => ['MixedArgument', 'MixedArrayOffset', 'MixedAssignment'], + ], ]; }