Skip to content

Commit 18c75a2

Browse files
authored
Fix substracted union type describe
1 parent d517bb4 commit 18c75a2

19 files changed

+52
-42
lines changed

src/Type/MixedType.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,19 @@ public function describe(VerbosityLevel $level): string
447447
function () use ($level): string {
448448
$description = 'mixed';
449449
if ($this->subtractedType !== null) {
450-
$description .= sprintf('~%s', $this->subtractedType->describe($level));
450+
$description .= $this->subtractedType instanceof UnionType
451+
? sprintf('~(%s)', $this->subtractedType->describe($level))
452+
: sprintf('~%s', $this->subtractedType->describe($level));
451453
}
452454

453455
return $description;
454456
},
455457
function () use ($level): string {
456458
$description = 'mixed';
457459
if ($this->subtractedType !== null) {
458-
$description .= sprintf('~%s', $this->subtractedType->describe($level));
460+
$description .= $this->subtractedType instanceof UnionType
461+
? sprintf('~(%s)', $this->subtractedType->describe($level))
462+
: sprintf('~%s', $this->subtractedType->describe($level));
459463
}
460464

461465
if ($this->isExplicitMixed) {

src/Type/ObjectType.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,9 @@ public function describe(VerbosityLevel $level): string
487487
$preciseWithSubtracted = function () use ($level): string {
488488
$description = $this->className;
489489
if ($this->subtractedType !== null) {
490-
$description .= sprintf('~%s', $this->subtractedType->describe($level));
490+
$description .= $this->subtractedType instanceof UnionType
491+
? sprintf('~(%s)', $this->subtractedType->describe($level))
492+
: sprintf('~%s', $this->subtractedType->describe($level));
491493
}
492494

493495
return $description;
@@ -538,7 +540,9 @@ private function describeCache(): string
538540
}
539541

540542
if ($this->subtractedType !== null) {
541-
$description .= sprintf('~%s', $this->subtractedType->describe(VerbosityLevel::cache()));
543+
$description .= $this->subtractedType instanceof UnionType
544+
? sprintf('~(%s)', $this->subtractedType->describe(VerbosityLevel::cache()))
545+
: sprintf('~%s', $this->subtractedType->describe(VerbosityLevel::cache()));
542546
}
543547

544548
$reflection = $this->classReflection;

src/Type/ObjectWithoutClassType.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ public function describe(VerbosityLevel $level): string
132132
function () use ($level): string {
133133
$description = 'object';
134134
if ($this->subtractedType !== null) {
135-
$description .= sprintf('~%s', $this->subtractedType->describe($level));
135+
$description .= $this->subtractedType instanceof UnionType
136+
? sprintf('~(%s)', $this->subtractedType->describe($level))
137+
: sprintf('~%s', $this->subtractedType->describe($level));
136138
}
137139

138140
return $description;

tests/PHPStan/Analyser/TypeSpecifierTest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class TypeSpecifierTest extends PHPStanTestCase
4444
{
4545

4646
private const FALSEY_TYPE_DESCRIPTION = '0|0.0|\'\'|\'0\'|array{}|false|null';
47-
private const TRUTHY_TYPE_DESCRIPTION = 'mixed~' . self::FALSEY_TYPE_DESCRIPTION;
47+
private const TRUTHY_TYPE_DESCRIPTION = 'mixed~(' . self::FALSEY_TYPE_DESCRIPTION . ')';
4848
private const SURE_NOT_FALSEY = '~' . self::FALSEY_TYPE_DESCRIPTION;
4949
private const SURE_NOT_TRUTHY = '~' . self::TRUTHY_TYPE_DESCRIPTION;
5050

@@ -819,10 +819,10 @@ public function dataCondition(): iterable
819819
new LNumber(3),
820820
),
821821
[
822-
'$n' => 'mixed~int<3, max>|true',
822+
'$n' => 'mixed~(int<3, max>|true)',
823823
],
824824
[
825-
'$n' => 'mixed~0.0|int<min, 2>|false|null',
825+
'$n' => 'mixed~(0.0|int<min, 2>|false|null)',
826826
],
827827
],
828828
[
@@ -831,10 +831,10 @@ public function dataCondition(): iterable
831831
new LNumber(PHP_INT_MIN),
832832
),
833833
[
834-
'$n' => 'mixed~int<' . PHP_INT_MIN . ', max>|true',
834+
'$n' => 'mixed~(int<' . PHP_INT_MIN . ', max>|true)',
835835
],
836836
[
837-
'$n' => 'mixed~0.0|false|null',
837+
'$n' => 'mixed~(0.0|false|null)',
838838
],
839839
],
840840
[
@@ -843,7 +843,7 @@ public function dataCondition(): iterable
843843
new LNumber(PHP_INT_MAX),
844844
),
845845
[
846-
'$n' => 'mixed~0.0|bool|int<min, ' . PHP_INT_MAX . '>|null',
846+
'$n' => 'mixed~(0.0|bool|int<min, ' . PHP_INT_MAX . '>|null)',
847847
],
848848
[
849849
'$n' => 'mixed',
@@ -858,7 +858,7 @@ public function dataCondition(): iterable
858858
'$n' => 'mixed~int<' . (PHP_INT_MIN + 1) . ', max>',
859859
],
860860
[
861-
'$n' => 'mixed~0.0|bool|int<min, ' . PHP_INT_MIN . '>|null',
861+
'$n' => 'mixed~(0.0|bool|int<min, ' . PHP_INT_MIN . '>|null)',
862862
],
863863
],
864864
[
@@ -867,10 +867,10 @@ public function dataCondition(): iterable
867867
new LNumber(PHP_INT_MAX),
868868
),
869869
[
870-
'$n' => 'mixed~0.0|int<min, ' . (PHP_INT_MAX - 1) . '>|false|null',
870+
'$n' => 'mixed~(0.0|int<min, ' . (PHP_INT_MAX - 1) . '>|false|null)',
871871
],
872872
[
873-
'$n' => 'mixed~int<' . PHP_INT_MAX . ', max>|true',
873+
'$n' => 'mixed~(int<' . PHP_INT_MAX . ', max>|true)',
874874
],
875875
],
876876
[
@@ -885,10 +885,10 @@ public function dataCondition(): iterable
885885
),
886886
),
887887
[
888-
'$n' => 'mixed~0.0|int<min, 2>|int<6, max>|false|null',
888+
'$n' => 'mixed~(0.0|int<min, 2>|int<6, max>|false|null)',
889889
],
890890
[
891-
'$n' => 'mixed~int<3, 5>|true',
891+
'$n' => 'mixed~(int<3, 5>|true)',
892892
],
893893
],
894894
[
@@ -1250,7 +1250,7 @@ public function dataCondition(): iterable
12501250
),
12511251
[
12521252
'$foo' => 'non-empty-array',
1253-
'count($foo)' => 'mixed~0.0|int<min, 1>|false|null',
1253+
'count($foo)' => 'mixed~(0.0|int<min, 1>|false|null)',
12541254
],
12551255
[],
12561256
],

tests/PHPStan/Analyser/nsrt/assert-empty.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ function ($var) {
2525

2626
function ($var) {
2727
assertNotEmpty($var);
28-
assertType("mixed~0|0.0|''|'0'|array{}|false|null", $var);
28+
assertType("mixed~(0|0.0|''|'0'|array{}|false|null)", $var);
2929
};

tests/PHPStan/Analyser/nsrt/bug-10189.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function file_managed_file_save_upload(): array {
2020
}
2121
assertType('non-empty-array|Bug10189\SomeInterface', $files);
2222
$files = array_filter($files);
23-
assertType("array<mixed~0|0.0|''|'0'|array{}|false|null>", $files);
23+
assertType("array<mixed~(0|0.0|''|'0'|array{}|false|null)>", $files);
2424

2525
return empty($files) ? [] : [1,2];
2626
}

tests/PHPStan/Analyser/nsrt/bug-3991.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static function email($config = null)
2626
assertType('array{}|null', $config);
2727
$config = new \stdClass();
2828
} elseif (! (is_array($config) || $config instanceof \stdClass)) {
29-
assertNativeType('mixed~0|0.0|\'\'|\'0\'|array{}|stdClass|false|null', $config);
29+
assertNativeType('mixed~(0|0.0|\'\'|\'0\'|array{}|stdClass|false|null)', $config);
3030
assertType('*NEVER*', $config);
3131
}
3232

tests/PHPStan/Analyser/nsrt/bug-3993.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public function doFoo($arguments)
1313
return;
1414
}
1515

16-
assertType('mixed~array{}|null', $arguments);
16+
assertType('mixed~(array{}|null)', $arguments);
1717

1818
array_shift($arguments);
1919

tests/PHPStan/Analyser/nsrt/bug-4117.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function broken(int $key)
3232
$item = $this->items[$key] ?? null;
3333
assertType('T of mixed~null (class Bug4117Types\GenericList, argument)|null', $item);
3434
if ($item) {
35-
assertType("T of mixed~0|0.0|''|'0'|array{}|false|null (class Bug4117Types\GenericList, argument)", $item);
35+
assertType("T of mixed~(0|0.0|''|'0'|array{}|false|null) (class Bug4117Types\GenericList, argument)", $item);
3636
} else {
3737
assertType("(array{}&T of mixed~null (class Bug4117Types\GenericList, argument))|(0.0&T of mixed~null (class Bug4117Types\GenericList, argument))|(0&T of mixed~null (class Bug4117Types\GenericList, argument))|(''&T of mixed~null (class Bug4117Types\GenericList, argument))|('0'&T of mixed~null (class Bug4117Types\GenericList, argument))|(T of mixed~null (class Bug4117Types\GenericList, argument)&false)|null", $item);
3838
}

tests/PHPStan/Analyser/nsrt/bug-7176.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function test(Suit $x): string {
2525
assertType('Bug7176Types\Suit::Spades', $x);
2626
return 'DOES NOT WORK';
2727
}
28-
assertType('Bug7176Types\Suit~Bug7176Types\Suit::Clubs|Bug7176Types\Suit::Spades', $x);
28+
assertType('Bug7176Types\Suit~(Bug7176Types\Suit::Clubs|Bug7176Types\Suit::Spades)', $x);
2929

3030
return match ($x) {
3131
Suit::Hearts => 'a',

0 commit comments

Comments
 (0)