diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php index c88b6c30536..e317de46e75 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php @@ -28,14 +28,12 @@ use Psalm\Type\Atomic\TFalse; use Psalm\Type\Atomic\TFloat; use Psalm\Type\Atomic\TInt; -use Psalm\Type\Atomic\TLiteralFloat; use Psalm\Type\Atomic\TLiteralInt; use Psalm\Type\Atomic\TLiteralString; use Psalm\Type\Atomic\TLowercaseString; use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString; use Psalm\Type\Atomic\TNonEmptyString; -use Psalm\Type\Atomic\TNonspecificLiteralInt; use Psalm\Type\Atomic\TNonspecificLiteralString; use Psalm\Type\Atomic\TNull; use Psalm\Type\Atomic\TString; diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.php index 5454f3b0206..0eeca85cc8c 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.php @@ -17,6 +17,7 @@ use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString; use Psalm\Type\Atomic\TNonEmptyString; use Psalm\Type\Atomic\TNonspecificLiteralInt; +use Psalm\Type\Atomic\TNonspecificLiteralString; use Psalm\Type\Union; use function in_array; @@ -55,20 +56,23 @@ public static function analyze( $all_literals = false; } elseif (!$non_empty) { // Check if all literals are nonempty + $non_empty = true; foreach ($casted_part_type->getAtomicTypes() as $atomic_literal) { - $non_empty = $atomic_literal instanceof TLiteralInt - || $atomic_literal instanceof TNonspecificLiteralInt - || $atomic_literal instanceof TLiteralFloat - || $atomic_literal instanceof TNonEmptyNonspecificLiteralString - || ($atomic_literal instanceof TLiteralString && $atomic_literal->value !== "") - ; + if (!$atomic_literal instanceof TLiteralInt + && !$atomic_literal instanceof TNonspecificLiteralInt + && !$atomic_literal instanceof TLiteralFloat + && !$atomic_literal instanceof TNonEmptyNonspecificLiteralString + && !($atomic_literal instanceof TLiteralString && $atomic_literal->value !== "") + ) { + $non_empty = false; + break; + } } } if ($literal_string !== null) { if ($casted_part_type->isSingleLiteral()) { $literal_string .= $casted_part_type->getSingleLiteral()->value; - if (!$non_empty && $literal_string !== "") {} } else { $literal_string = null; } @@ -121,7 +125,11 @@ public static function analyze( } else { $new_type = new Union([new TNonEmptyString()]); } - + } elseif ($all_literals) { + $new_type = new Union([new TNonspecificLiteralString()]); + } + if (isset($new_type)) { + assert($new_type instanceof Union); $new_type->parent_nodes = $stmt_type->parent_nodes; $stmt_type = $new_type; } diff --git a/tests/BinaryOperationTest.php b/tests/BinaryOperationTest.php index a1d761e1ae3..241e573e27d 100644 --- a/tests/BinaryOperationTest.php +++ b/tests/BinaryOperationTest.php @@ -720,6 +720,16 @@ function foo(string $s1): string { ', 'assertions' => ['$concatenated===' => 'non-empty-literal-string'], ], + 'encapsedPossiblyEmptyLiteralString' => [ + ' ['$interpolated===' => 'literal-string'], + ], 'literalIntConcatCreatesLiteral' => [ '