Skip to content

Commit

Permalink
DateTimeImmutable removed from DateTimeInterface results in DateTime
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jul 14, 2021
1 parent f5e88ae commit 5eb96f5
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/Type/TypeCombinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,17 @@ public static function remove(Type $fromType, Type $typeToRemove): Type
if ($typeToRemove instanceof AccessoryNonEmptyStringType) {
return new ConstantStringType('');
}
} elseif ($fromType instanceof SubtractableType) {
} elseif ($fromType instanceof ObjectType && $fromType->getClassName() === \DateTimeInterface::class) {
if ($typeToRemove instanceof ObjectType && $typeToRemove->getClassName() === \DateTimeImmutable::class) {
return new ObjectType(\DateTime::class);
}

if ($typeToRemove instanceof ObjectType && $typeToRemove->getClassName() === \DateTime::class) {
return new ObjectType(\DateTimeImmutable::class);
}
}

if ($fromType instanceof SubtractableType) {
$typeToSubtractFrom = $fromType;
if ($fromType instanceof TemplateType) {
$typeToSubtractFrom = $fromType->getBound();
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/generic-object-lower-bound.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/class-reflection-interfaces.php');
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Methods/data/bug-4415.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5259.php');
}

/**
Expand Down
30 changes: 30 additions & 0 deletions tests/PHPStan/Analyser/data/bug-5259.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Bug5259Types;

use DateTime;
use DateTimeImmutable;
use function PHPStan\Testing\assertType;

class Foo
{

public function doFoo(\DateTimeInterface $dtin): void
{
if ($dtin instanceof \DateTimeImmutable) {
return;
}

assertType(DateTime::class, $dtin);
}

public function doBar(\DateTimeInterface $dtin): void
{
if ($dtin instanceof \DateTime) {
return;
}

assertType(DateTimeImmutable::class, $dtin);
}

}
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/data/native-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public function doIfElse(\DateTimeInterface $date): void
assertNativeType(\DateTimeImmutable::class, $date);
} else {
assertType('*NEVER*', $date);
assertNativeType('DateTimeInterface~DateTimeImmutable', $date);
assertNativeType('DateTime', $date);
}

assertType(\DateTimeImmutable::class, $date);
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -435,4 +435,10 @@ public function testBug1971(): void
]);
}

public function testBug5259(): void
{
$this->checkThisOnly = false;
$this->analyse([__DIR__ . '/data/bug-5259.php'], []);
}

}
15 changes: 15 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug-5259.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Bug5259;

class HelloWorld
{

/** @var \DateTimeImmutable */
private $date;

public function __construct(\DateTimeInterface $date)
{
$this->date = $date instanceof \DateTimeImmutable ? $date : \DateTimeImmutable::createFromMutable($date);
}
}

0 comments on commit 5eb96f5

Please sign in to comment.