From 4b0e3d0c06a213985c241232a6206e2a8f9a5997 Mon Sep 17 00:00:00 2001 From: orklah Date: Thu, 21 Oct 2021 18:10:20 +0200 Subject: [PATCH] improve empty/falsy --- .../LanguageServer/ProtocolStreamReader.php | 2 +- .../Type/SimpleAssertionReconciler.php | 182 ++++-------------- 2 files changed, 36 insertions(+), 148 deletions(-) diff --git a/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php b/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php index 90daa8949..9a47793e6 100644 --- a/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php +++ b/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php @@ -118,7 +118,7 @@ class ProtocolStreamReader implements ProtocolReader $this->emit('message', [$msg]); /** * @psalm-suppress DocblockTypeContradiction - * @psalm-suppress ParadoxicalCondition + * @psalm-suppress RedundantConditionGivenDocblockType */ if (!$this->is_accepting_new_requests) { // If we fork, don't read any bytes in the input buffer from the worker process. diff --git a/src/Psalm/Internal/Type/SimpleAssertionReconciler.php b/src/Psalm/Internal/Type/SimpleAssertionReconciler.php index c89d88c9b..64e014e20 100644 --- a/src/Psalm/Internal/Type/SimpleAssertionReconciler.php +++ b/src/Psalm/Internal/Type/SimpleAssertionReconciler.php @@ -48,6 +48,7 @@ use Psalm\Type\Atomic\TString; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Union; +use function assert; use function count; use function explode; use function get_class; @@ -2244,26 +2245,18 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler } if ($did_remove_type && $existing_var_type->getAtomicTypes() === []) { + //every type was removed, this is an impossible assertion if ($code_location && $key) { - if ($existing_var_type->from_docblock) { - $issue = new DocblockTypeContradiction( - 'Found a paradox when evaluating ' . $key - . ' of type ' . $old_var_type_string - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - null - ); - } else { - $issue = new ParadoxicalCondition( - 'Found a paradox when evaluating ' . $key - . ' of type ' . $old_var_type_string - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location - ); - } - if (IssueBuffer::accepts($issue, $suppressed_issues)) { - // fall through - } + self::triggerIssueForImpossible( + $existing_var_type, + $old_var_type_string, + $key, + $assertion, + false, + $negated, + $code_location, + $suppressed_issues + ); } $failed_reconciliation = 2; @@ -2271,6 +2264,26 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler return Type::getEmpty(); } + if (!$did_remove_type) { + //nothing was removed, this is a redundant assertion + if ($code_location && $key) { + self::triggerIssueForImpossible( + $existing_var_type, + $old_var_type_string, + $key, + $assertion, + true, + $negated, + $code_location, + $suppressed_issues + ); + } + + $failed_reconciliation = 1; + + return $existing_var_type; + } + if ($existing_var_type->hasType('bool')) { $existing_var_type->removeType('bool'); $existing_var_type->addType(new TFalse()); @@ -2292,33 +2305,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler if (get_class($mixed_atomic_type) === TMixed::class) { $existing_var_type->removeType('mixed'); $existing_var_type->addType(new TEmptyMixed()); - } elseif ($existing_var_type->isSingle() && $mixed_atomic_type instanceof TEmptyMixed) { - if ($code_location && $key && !$did_remove_type) { - if ($existing_var_type->from_docblock) { - $issue = new RedundantConditionGivenDocblockType( - 'Found a redundant condition when evaluating ' . $key - . ' of type ' . $existing_var_type->getId() - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - $existing_var_type->getId() . ' ' . $assertion - ); - } else { - $issue = new RedundantCondition( - 'Found a redundant condition when evaluating ' . $key - . ' of type ' . $existing_var_type->getId() - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - $existing_var_type->getId() . ' ' . $assertion - ); - } - if (IssueBuffer::accepts($issue, $suppressed_issues)) { - // fall through - } - } - } - - if ($existing_var_type->isSingle()) { - return $existing_var_type; } } @@ -2328,35 +2314,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler if (get_class($scalar_atomic_type) === TScalar::class) { $existing_var_type->removeType('scalar'); $existing_var_type->addType(new TEmptyScalar()); - } elseif ($existing_var_type->isSingle() && - $scalar_atomic_type instanceof TEmptyScalar - ) { - if ($code_location && $key && !$did_remove_type) { - if ($existing_var_type->from_docblock) { - $issue = new RedundantConditionGivenDocblockType( - 'Found a redundant condition when evaluating ' . $key - . ' of type ' . $existing_var_type->getId() - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - $existing_var_type->getId() . ' ' . $assertion - ); - } else { - $issue = new RedundantCondition( - 'Found a redundant condition when evaluating ' . $key - . ' of type ' . $existing_var_type->getId() - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - $existing_var_type->getId() . ' ' . $assertion - ); - } - if (IssueBuffer::accepts($issue, $suppressed_issues)) { - // fall through - } - } - } - - if ($existing_var_type->isSingle()) { - return $existing_var_type; } } @@ -2376,33 +2333,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler } elseif (get_class($string_atomic_type) === TNonEmptyNonspecificLiteralString::class) { $existing_var_type->removeType('string'); $existing_var_type->addType(new TLiteralString('0')); - } elseif ($existing_var_type->isSingle() && $string_atomic_type instanceof TNonFalsyString) { - if ($code_location && $key && !$did_remove_type) { - if ($existing_var_type->from_docblock) { - $issue = new RedundantConditionGivenDocblockType( - 'Found a redundant condition when evaluating ' . $key - . ' of type ' . $existing_var_type->getId() - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - $existing_var_type->getId() . ' ' . $assertion - ); - } else { - $issue = new RedundantCondition( - 'Found a redundant condition when evaluating ' . $key - . ' of type ' . $existing_var_type->getId() - . ' and trying to reconcile it with a ' . $assertion . ' assertion', - $code_location, - $existing_var_type->getId() . ' ' . $assertion - ); - } - if (IssueBuffer::accepts($issue, $suppressed_issues)) { - // fall through - } - } - } - - if ($existing_var_type->isSingle()) { - return $existing_var_type; } } @@ -2420,28 +2350,16 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler $existing_var_type->removeType('int'); $existing_var_type->addType(new TLiteralInt(0)); } - - if ($existing_var_type->isSingle()) { - return $existing_var_type; - } } if ($existing_var_type->hasFloat()) { $existing_var_type->removeType('float'); $existing_var_type->addType(new TLiteralFloat(0.0)); - - if ($existing_var_type->isSingle()) { - return $existing_var_type; - } } if ($existing_var_type->hasNumeric()) { $existing_var_type->removeType('numeric'); $existing_var_type->addType(new TEmptyNumeric()); - - if ($existing_var_type->isSingle()) { - return $existing_var_type; - } } foreach ($existing_var_atomic_types as $existing_var_atomic_type) { @@ -2461,8 +2379,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler $template_did_fail ); - $did_remove_type = true; - if (!$template_did_fail) { $existing_var_type->addType($existing_var_atomic_type); } @@ -2470,36 +2386,8 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler } } - if ((!$did_remove_type || empty($existing_var_type->getAtomicTypes())) - && ($assertion !== 'empty' || !$existing_var_type->possibly_undefined) - ) { - if ($key && $code_location) { - self::triggerIssueForImpossible( - $existing_var_type, - $old_var_type_string, - $key, - $assertion, - !$did_remove_type, - $negated, - $code_location, - $suppressed_issues - ); - } - - if (!$did_remove_type) { - $failed_reconciliation = 1; - } - } - - /** @psalm-suppress RedundantCondition can be empty after removing above */ - if ($existing_var_type->getAtomicTypes()) { - return $existing_var_type; - } - - $failed_reconciliation = 2; - - return $assertion === 'empty' && $existing_var_type->possibly_undefined - ? Type::getEmpty() - : Type::getMixed(); + /** @psalm-suppress RedundantCondition safety check in case we removed something that shouldn't be removed */ + assert($existing_var_type->getAtomicTypes() !== []); + return $existing_var_type; } }