diff --git a/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php index fa4b85246..aa3d1b490 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php @@ -191,7 +191,7 @@ class ForeachAnalyzer && $type_location && isset($context->vars_in_scope[$var_comment->var_id]) && $context->vars_in_scope[$var_comment->var_id]->getId() === $comment_type->getId() - && !$comment_type->isMixed() + && !$comment_type->isMixed(true) ) { $project_analyzer = $statements_analyzer->getProjectAnalyzer(); diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php index 95b2adf34..6f0053468 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php @@ -270,7 +270,7 @@ class AssignmentAnalyzer && $extended_var_id && (!$not_ignored_docblock_var_ids || isset($not_ignored_docblock_var_ids[$extended_var_id])) && $temp_assign_value_type->getId() === $comment_type->getId() - && !$comment_type->isMixed() + && !$comment_type->isMixed(true) ) { if ($codebase->alter_code && isset($statements_analyzer->getProjectAnalyzer()->getIssuesToFix()['UnnecessaryVarAnnotation']) diff --git a/src/Psalm/Type/UnionTrait.php b/src/Psalm/Type/UnionTrait.php index bd7a1bdb5..00e254462 100644 --- a/src/Psalm/Type/UnionTrait.php +++ b/src/Psalm/Type/UnionTrait.php @@ -795,9 +795,18 @@ trait UnionTrait /** * @psalm-mutation-free */ - public function isMixed(): bool + public function isMixed(bool $check_templates = false): bool { - return isset($this->types['mixed']) && count($this->types) === 1; + return count( + array_filter( + $this->types, + static fn($type): bool => $type instanceof TMixed + || ($check_templates + && $type instanceof TTemplateParam + && $type->as->isMixed() + ) + ), + ) === count($this->types); } /** diff --git a/tests/Template/ClassTemplateTest.php b/tests/Template/ClassTemplateTest.php index 74981bb2f..327ebb2b7 100644 --- a/tests/Template/ClassTemplateTest.php +++ b/tests/Template/ClassTemplateTest.php @@ -4112,6 +4112,32 @@ class ClassTemplateTest extends TestCase '$t===' => '\'\'', ], ], + 'mixedAssignment' => [ + 'code' => 'normalize($value); + $this->value = $value; + } + + /** + * @psalm-param T $value + * @psalm-return T + */ + protected function normalize($value) + { + return $value; + } + } + ', + ], ]; }