From 7d33db0d19d85e1c318ee2261f548513f0905800 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Thu, 16 Nov 2017 01:11:46 -0500 Subject: [PATCH] Fix issue with array unification after scanning --- .../Statements/Block/SwitchChecker.php | 2 + .../Statements/Expression/FetchChecker.php | 54 ++++++++++++++++--- tests/ArrayAccessTest.php | 13 +++++ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/Psalm/Checker/Statements/Block/SwitchChecker.php b/src/Psalm/Checker/Statements/Block/SwitchChecker.php index 16cb3c9a2..203c1d979 100644 --- a/src/Psalm/Checker/Statements/Block/SwitchChecker.php +++ b/src/Psalm/Checker/Statements/Block/SwitchChecker.php @@ -172,6 +172,8 @@ class SwitchChecker if ($possibly_redefined_vars === null) { $possibly_redefined_vars = $case_redefined_vars; } else { + $possibly_redefined_vars = []; + foreach ($case_redefined_vars as $var_id => $type) { if (!isset($possibly_redefined_vars[$var_id])) { $possibly_redefined_vars[$var_id] = $type; diff --git a/src/Psalm/Checker/Statements/Expression/FetchChecker.php b/src/Psalm/Checker/Statements/Expression/FetchChecker.php index ff0c96437..13a1967af 100644 --- a/src/Psalm/Checker/Statements/Expression/FetchChecker.php +++ b/src/Psalm/Checker/Statements/Expression/FetchChecker.php @@ -1113,7 +1113,15 @@ class FetchChecker } } } elseif ($type instanceof Type\Atomic\TArray && $value_index !== null) { - $stmt->inferredType = $type->type_params[$value_index]; + if (!isset($stmt->inferredType)) { + $stmt->inferredType = $type->type_params[$value_index]; + } else { + $stmt->inferredType = Type::combineUnionTypes( + $stmt->inferredType, + $type->type_params[$value_index] + ); + } + if ($stmt->inferredType->isEmpty()) { if (IssueBuffer::accepts( new EmptyArrayAccess( @@ -1133,10 +1141,26 @@ class FetchChecker if ($string_key_value || $int_key_value !== null) { if ($string_key_value && isset($type->properties[$string_key_value])) { $has_valid_offset = true; - $stmt->inferredType = clone $type->properties[$string_key_value]; + + if (!isset($stmt->inferredType)) { + $stmt->inferredType = clone $type->properties[$string_key_value]; + } else { + $stmt->inferredType = Type::combineUnionTypes( + $stmt->inferredType, + $type->properties[$string_key_value] + ); + } } elseif ($int_key_value !== null && isset($type->properties[(string)$int_key_value])) { $has_valid_offset = true; - $stmt->inferredType = clone $type->properties[(string)$int_key_value]; + + if (!isset($stmt->inferredType)) { + $stmt->inferredType = clone $type->properties[(string)$int_key_value]; + } else { + $stmt->inferredType = Type::combineUnionTypes( + $stmt->inferredType, + $type->properties[(string)$int_key_value] + ); + } } else { $invalid_offset_types[] = '"' . ($string_key_value ?: $int_key_value) . '"'; } @@ -1145,8 +1169,16 @@ class FetchChecker $used_key_type, Type::getString() )) { + if (!isset($stmt->inferredType)) { + $stmt->inferredType = $type->getGenericTypeParam(); + } else { + $stmt->inferredType = Type::combineUnionTypes( + $stmt->inferredType, + $type->getGenericTypeParam() + ); + } + $has_valid_offset = true; - $stmt->inferredType = $type->getGenericTypeParam(); } else { $invalid_offset_types[] = 'string'; } @@ -1165,7 +1197,15 @@ class FetchChecker $has_valid_offset = true; } - $stmt->inferredType = Type::getString(); + if (!isset($stmt->inferredType)) { + $stmt->inferredType = Type::getString(); + } else { + $stmt->inferredType = Type::combineUnionTypes( + $stmt->inferredType, + Type::getString() + ); + } + continue; } @@ -1240,7 +1280,7 @@ class FetchChecker if ($has_valid_offset) { if (IssueBuffer::accepts( new PossiblyInvalidArrayOffset( - 'Cannot access value on array variable ' . $var_id . ' using ' . $used_key_type + 'Cannot access value on variable ' . $var_id . ' using ' . $used_key_type . ' offset, expecting ' . $invalid_offset_type, new CodeLocation($statements_checker->getSource(), $stmt) ), @@ -1251,7 +1291,7 @@ class FetchChecker } else { if (IssueBuffer::accepts( new InvalidArrayOffset( - 'Cannot access value on array variable ' . $var_id . ' using ' . $used_key_type + 'Cannot access value on variable ' . $var_id . ' using ' . $used_key_type . ' offset, expecting ' . $invalid_offset_type, new CodeLocation($statements_checker->getSource(), $stmt) ), diff --git a/tests/ArrayAccessTest.php b/tests/ArrayAccessTest.php index e79494714..9bec60a4d 100644 --- a/tests/ArrayAccessTest.php +++ b/tests/ArrayAccessTest.php @@ -119,6 +119,19 @@ class ArrayAccessTest extends TestCase $y = $x["a"];', 'error_message' => 'PossiblyInvalidArrayOffset', ], + 'possiblyInvalidArrayAccessWithNestedArray' => [ + '>|string + * @return string + */ + function return_array() { + return rand() % 5 > 3 ? [["key" => 3.5]] : "key:3.5"; + } + $result = return_array(); + $v = $result[0]["key"];', + 'error_message' => 'PossiblyInvalidArrayOffset', + ], 'possiblyInvalidArrayAccess' => [ ' 5 ? 5 : ["hello"];