diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php index d34a23db352..e2190597bed 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php @@ -265,7 +265,7 @@ public static function analyze( if (!$naive_property_exists) { if ($class_storage->namedMixins) { - [$lhs_type_part, $class_storage, $naive_property_exists, $property_id, $fq_class_name] + [$lhs_type_part, $class_storage, , $naive_property_exists, $property_id, $fq_class_name] = self::handleRegularMixins( $class_storage, $lhs_type_part, @@ -1273,6 +1273,7 @@ private static function handleRegularMixins( StatementsAnalyzer $statements_analyzer, string $fq_class_name ): array { + $property_exists = false; $naive_property_exists = false; foreach ($class_storage->namedMixins as $mixin) { $new_property_id = $mixin->value . '::$' . $prop_name; @@ -1299,6 +1300,7 @@ private static function handleRegularMixins( $lhs_type_part = $mixin; $class_storage = $new_class_storage; + $property_exists = true; if (!isset($new_class_storage->pseudo_property_get_types['$' . $prop_name])) { $naive_property_exists = true; } @@ -1306,9 +1308,49 @@ private static function handleRegularMixins( $property_id = $new_property_id; } } + if (!$property_exists) { + foreach ($class_storage->namedMixins as $mixin) { + try { + $mixin_class_storage = $codebase->classlike_storage_provider->get($mixin->value); + } catch (InvalidArgumentException $e) { + continue; + } + $mixin_lhs_type_part = $mixin; + $mixin_fq_class_name = $mixin_class_storage->name; + + [ + $new_lhs_type_part, + $new_class_storage, + $property_exists, + $naive_property_exists, + $new_property_id, + $new_fq_class_name, + ] = self::handleRegularMixins( + $mixin_class_storage, + $mixin_lhs_type_part, + $prop_name, + $in_assignment, + $codebase, + $context, + $property_id, + $stmt, + $statements_analyzer, + $mixin_fq_class_name, + ); + + if ($property_exists) { + $fq_class_name = $new_fq_class_name; + $lhs_type_part = $new_lhs_type_part; + $class_storage = $new_class_storage; + $property_id = $new_property_id; + break; + } + } + } return [ $lhs_type_part, $class_storage, + $property_exists, $naive_property_exists, $property_id, $fq_class_name,