Skip to content

Commit

Permalink
Fix subtracting types from union template types
Browse files Browse the repository at this point in the history
  • Loading branch information
rvanvelzen committed Sep 29, 2023
1 parent 8a6d6a5 commit ec957a9
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
13 changes: 10 additions & 3 deletions src/Type/Generic/TemplateTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,18 @@ public function traverseSimultaneously(Type $right, callable $cb): Type

public function tryRemove(Type $typeToRemove): ?Type
{
if ($this->getBound()->isSuperTypeOf($typeToRemove)->yes()) {
return $this->subtract($typeToRemove);
$bound = TypeCombinator::remove($this->getBound(), $typeToRemove);
if ($this->getBound() === $bound) {
return null;
}

return null;
return TemplateTypeFactory::create(
$this->getScope(),
$this->getName(),
$bound,
$this->getVariance(),
$this->getStrategy(),
);
}

public function toPhpDocNode(): TypeNode
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 @@ -1342,6 +1342,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/nullsafe-vs-scalar.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8517.php');
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Functions/data/bug-9803.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9939.php');
}

/**
Expand Down
63 changes: 63 additions & 0 deletions tests/PHPStan/Analyser/data/bug-9939.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php declare(strict_types = 1);

namespace Bug9939;

use function PHPStan\Testing\assertType;

enum Combinator
{
case NEXT_SIBLING;
case CHILD;
case FOLLOWING_SIBLING;

public function getText(): string
{
return match ($this) {
self::NEXT_SIBLING => '+',
self::CHILD => '>',
self::FOLLOWING_SIBLING => '~',
};
}
}

/**
* @template T of string|\Stringable|array<string|\Stringable>|Combinator|null
*/
class CssValue
{
/**
* @param T $value
*/
public function __construct(private readonly mixed $value)
{
}

/**
* @return T
*/
public function getValue(): mixed
{
return $this->value;
}

public function __toString(): string
{
assertType('T of array<string|Stringable>|Bug9939\Combinator|string|Stringable|null (class Bug9939\CssValue, argument)', $this->value);

if ($this->value instanceof Combinator) {
assertType('T of Bug9939\Combinator (class Bug9939\CssValue, argument)', $this->value);
return $this->value->getText();
}

assertType('T of array<string|Stringable>|string|Stringable|null (class Bug9939\CssValue, argument)', $this->value);

if (\is_array($this->value)) {
assertType('T of array<string|Stringable> (class Bug9939\CssValue, argument)', $this->value);
return implode($this->value);
}

assertType('T of string|Stringable|null (class Bug9939\CssValue, argument)', $this->value);

return (string) $this->value;
}
}

0 comments on commit ec957a9

Please sign in to comment.