diff --git a/src/Psalm/Internal/Type/NegatedAssertionReconciler.php b/src/Psalm/Internal/Type/NegatedAssertionReconciler.php index bcd0fb30707..f091c75b598 100644 --- a/src/Psalm/Internal/Type/NegatedAssertionReconciler.php +++ b/src/Psalm/Internal/Type/NegatedAssertionReconciler.php @@ -208,6 +208,21 @@ public static function reconcile( return $existing_var_type; } + if (!$is_equality + && ($assertion === 'DateTime' || $assertion === 'DateTimeImmutable') + && isset($existing_var_atomic_types['DateTimeInterface']) + ) { + $existing_var_type->removeType('DateTimeInterface'); + + if ($assertion === 'DateTime') { + $existing_var_type->addType(new TNamedObject('DateTimeImmutable')); + } else { + $existing_var_type->addType(new TNamedObject('DateTime')); + } + + return $existing_var_type; + } + if (strtolower($assertion) === 'traversable' && isset($existing_var_atomic_types['iterable']) ) { diff --git a/tests/TypeReconciliation/ReconcilerTest.php b/tests/TypeReconciliation/ReconcilerTest.php index a328306d516..d122def8c55 100644 --- a/tests/TypeReconciliation/ReconcilerTest.php +++ b/tests/TypeReconciliation/ReconcilerTest.php @@ -110,6 +110,8 @@ public function providerTestReconcilation(): array 'notSomeClassWithSomeClassPipeBool' => ['bool', '!SomeClass', 'SomeClass|bool'], 'notSomeClassWithSomeClassPipeNull' => ['null', '!SomeClass', 'SomeClass|null'], 'notSomeClassWithAPipeB' => ['B', '!A', 'A|B'], + 'notDateTimeWithDateTimeInterface' => ['DateTimeImmutable', '!DateTime', 'DateTimeInterface'], + 'notDateTimeImmutableWithDateTimeInterface' => ['DateTime', '!DateTimeImmutable', 'DateTimeInterface'], 'myObjectWithSomeClassPipeBool' => ['SomeClass', 'SomeClass', 'SomeClass|bool'], 'myObjectWithAPipeB' => ['A', 'A', 'A|B'], diff --git a/tests/TypeReconciliation/TypeTest.php b/tests/TypeReconciliation/TypeTest.php index 1565fbbd593..75f42828c4f 100644 --- a/tests/TypeReconciliation/TypeTest.php +++ b/tests/TypeReconciliation/TypeTest.php @@ -1073,6 +1073,36 @@ function foo($arr): void { */ function consume($input): void{}' ], + 'notDateTimeWithDateTimeInterface' => [ + 'add($dateInterval); + + return $dateTime; + } else { + return $dateTime->add($dateInterval); + } + } + ', + ], + 'notDateTimeImmutableWithDateTimeInterface' => [ + 'add($dateInterval); + } else { + $dateTime->add($dateInterval); + + return $dateTime; + } + } + ', + ], ]; }