From d1cf9d61ba6cf76b30b206dfbbfbdb4e559092bb Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Fri, 1 Mar 2019 00:50:22 -0500 Subject: [PATCH] Fix #1398 - improve casting rules for resource --- .../Statements/ExpressionAnalyzer.php | 50 ++++++++++--------- tests/ToStringTest.php | 9 ++++ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php index d2b42c428..1c9970794 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php @@ -416,33 +416,35 @@ class ExpressionAnalyzer return false; } - $container_type = Type::getString(); - - if (isset($stmt->expr->inferredType) - && !$stmt->expr->inferredType->hasMixed() - && !isset($stmt->expr->inferredType->getTypes()['resource']) - && !TypeAnalyzer::isContainedBy( - $statements_analyzer->getCodebase(), - $stmt->expr->inferredType, - $container_type, - true, - false, - $has_scalar_match - ) - && !$has_scalar_match - ) { - if (IssueBuffer::accepts( - new InvalidCast( - $stmt->expr->inferredType->getId() . ' cannot be cast to ' . $container_type, - new CodeLocation($statements_analyzer->getSource(), $stmt) - ), - $statements_analyzer->getSuppressedIssues() - )) { - return false; + if (isset($stmt->expr->inferredType)) { + foreach ($stmt->expr->inferredType->getTypes() as $atomic_type) { + if (!$atomic_type instanceof TMixed + && !$atomic_type instanceof Type\Atomic\TResource + && !$atomic_type instanceof TNull + && !TypeAnalyzer::isAtomicContainedBy( + $statements_analyzer->getCodebase(), + $atomic_type, + new TString(), + true, + false, + $has_scalar_match + ) + && !$has_scalar_match + ) { + if (IssueBuffer::accepts( + new InvalidCast( + $atomic_type->getId() . ' cannot be cast to string', + new CodeLocation($statements_analyzer->getSource(), $stmt) + ), + $statements_analyzer->getSuppressedIssues() + )) { + return false; + } + } } } - $stmt->inferredType = $container_type; + $stmt->inferredType = Type::getString(); } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) { if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) { return false; diff --git a/tests/ToStringTest.php b/tests/ToStringTest.php index aac9bb5db..227ae9145 100644 --- a/tests/ToStringTest.php +++ b/tests/ToStringTest.php @@ -186,6 +186,15 @@ class ToStringTest extends TestCase takesString($a);', 'error_message' => 'InvalidArgument', ], + 'resourceOrFalseToString' => [ + ' 'InvalidCast', + ], ]; } }