diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php index 92025d0bb..41c04ed79 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php @@ -721,19 +721,27 @@ final class ClassConstAnalyzer // Check assigned type matches docblock type if ($assigned_type = $statements_analyzer->node_data->getType($const->value)) { - if ($const_storage->type !== null + $const_storage_type = $const_storage->type; + + if ($const_storage_type !== null && $const_storage->stmt_location !== null - && $assigned_type !== $const_storage->type + && $assigned_type !== $const_storage_type + // Check if this type was defined via a dockblock or type hint otherwise the inferred type + // should always match the assigned type and we don't even need to do additional checks + // There is an issue with constants over a certain length where additional values + // are added to fallback_params in the assigned_type but not in const_storage_type + // which causes a false flag for this error to appear. Usually happens with arrays + && ($const_storage_type->from_docblock || $const_storage_type->from_property) && !UnionTypeComparator::isContainedBy( $statements_analyzer->getCodebase(), $assigned_type, - $const_storage->type, + $const_storage_type, ) ) { IssueBuffer::maybeAdd( new InvalidConstantAssignmentValue( "{$class_storage->name}::{$const->name->name} with declared type " - . "{$const_storage->type->getId()} cannot be assigned type {$assigned_type->getId()}", + . "{$const_storage_type->getId()} cannot be assigned type {$assigned_type->getId()}", $const_storage->stmt_location, "{$class_storage->name}::{$const->name->name}", ), diff --git a/tests/ConstantTest.php b/tests/ConstantTest.php index 828f2ea65..68b10f2b6 100644 --- a/tests/ConstantTest.php +++ b/tests/ConstantTest.php @@ -824,6 +824,242 @@ class ConstantTest extends TestCase A::foo(2); A::foo(3);', ], + 'tooLongArrayInvalidConstantAssignmentValueFalsePositiveWithArray' => [ + 'code' => ' null, + "01" => null, + "02" => null, + "03" => null, + "04" => null, + "05" => null, + "06" => null, + "07" => null, + "08" => null, + "09" => null, + "10" => null, + "11" => null, + "12" => null, + "13" => null, + "14" => null, + "15" => null, + "16" => null, + "17" => null, + "18" => null, + "19" => null, + "20" => null, + "21" => null, + "22" => null, + "23" => null, + "24" => null, + "25" => null, + "26" => null, + "27" => null, + "28" => null, + "29" => null, + "30" => null, + "31" => null, + "32" => null, + "33" => null, + "34" => null, + "35" => null, + "36" => null, + "37" => null, + "38" => null, + "39" => null, + "40" => null, + "41" => null, + "42" => null, + "43" => null, + "44" => null, + "45" => null, + "46" => null, + "47" => null, + "48" => null, + "49" => null, + "50" => null, + "51" => null, + "52" => null, + "53" => null, + "54" => null, + "55" => null, + "56" => null, + "57" => null, + "58" => null, + "59" => null, + "60" => null, + "61" => null, + "62" => null, + "63" => null, + "64" => null, + "65" => null, + "66" => null, + "67" => null, + "68" => null, + "69" => null, + "70" => self::SUCCEED, + "71" => self::FAIL, + "72" => null, + "73" => null, + "74" => null, + "75" => null, + "76" => null, + "77" => null, + "78" => null, + "79" => null, + "80" => null, + "81" => null, + "82" => null, + "83" => null, + "84" => null, + "85" => null, + "86" => null, + "87" => null, + "88" => null, + "89" => null, + "90" => null, + "91" => null, + "92" => null, + "93" => null, + "94" => null, + "95" => null, + "96" => null, + "97" => null, + "98" => null, + "99" => null, + "100" => null, + "101" => null, + ]; + + const SUCCEED = "SUCCEED"; + const FAIL = "FAIL"; + + public static function will_succeed(string $code) : bool { + // Seems to fail when the array has over 100+ entries, and at least one value references + // another constant from the same class (even nested) + return (self::LOOKUP[$code] ?? null) === self::SUCCEED; + } + }', + ], + 'tooLongArrayInvalidConstantAssignmentValueFalsePositiveWithList' => [ + 'code' => ' [ 'code' => '