1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Fix manipulation of intersection types, arrow functions, foreign static types, T|false|null unions.

This commit is contained in:
Daniil Gentili 2021-10-13 11:13:43 +02:00
parent 1574751aef
commit 1c99af205b
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
3 changed files with 122 additions and 4 deletions

View File

@ -8,6 +8,7 @@ use Psalm\Type\Atomic;
use function array_map;
use function implode;
use function strrpos;
use function substr;
/**
@ -127,7 +128,14 @@ class TNamedObject extends Atomic
return $php_major_version >= 8 ? 'static' : 'self';
}
return $this->toNamespacedString($namespace, $aliased_classes, $this_class, false);
$result = $this->toNamespacedString($namespace, $aliased_classes, $this_class, false);
$intersection = strrpos($result, '&');
if ($intersection === false ||
($intersection !== false && $php_major_version >= 8 && $php_minor_version >= 1)
) {
return $result;
}
return substr($result, $intersection+1);
}
public function canBeFullyExpressedInPhp(int $php_major_version, int $php_minor_version): bool

View File

@ -23,6 +23,7 @@ use function array_values;
use function count;
use function get_class;
use function implode;
use function ksort;
use function reset;
use function sort;
use function strpos;
@ -497,7 +498,7 @@ class Union implements TypeNode
$nullable = false;
if (isset($types['null']) && count($types) === 2) {
if (isset($types['null']) && count($types) > 1) {
unset($types['null']);
$nullable = true;
@ -530,7 +531,12 @@ class Union implements TypeNode
}
if ($falsable) {
return ($nullable ? '?' : '') . implode('|', array_unique($php_types)) . '|false';
if ($nullable) {
$php_types['null'] = 'null';
}
$php_types['false'] = 'false';
ksort($php_types);
return implode('|', array_unique($php_types));
}
return ($nullable ? '?' : '') . implode('|', array_unique($php_types));

View File

@ -731,7 +731,111 @@ class ReturnTypeManipulationTest extends FileManipulationTestCase
['MissingReturnType'],
false,
true,
]
],
'OrFalseNullInReturn' => [
'<?php
function a() {
/** @var array|false|null $a */
$a = false;
return $a;
}',
'<?php
function a(): array|false|null {
/** @var array|false|null $a */
$a = false;
return $a;
}',
'8.0',
['MissingReturnType'],
false,
true,
],
'OrFalseNullInReturn' => [
'<?php
function a() {
/** @var array|false|null $a */
$a = false;
return $a;
}',
'<?php
function a(): array|false|null {
/** @var array|false|null $a */
$a = false;
return $a;
}',
'8.0',
['MissingReturnType'],
false,
true,
],
'ForeignStatic' => [
'<?php
class a {
public function g(): static { return $this; }
}
class b extends a {}
class c {
public function a() { return (new a)->g(); }
public function b() { return (new b)->g(); }
}
',
'<?php
class a {
public function g(): static { return $this; }
}
class b extends a {}
class c {
public function a(): a { return (new a)->g(); }
public function b(): b { return (new b)->g(); }
}
',
'8.0',
['MissingReturnType'],
false,
true,
],
'ForeignStaticIntersection' => [
'<?php
class a {
public function g(): static { return $this; }
}
class b extends a {}
class c {
public function a() { return (new a)->g(); }
public function b() { return (new b)->g(); }
}
',
'<?php
class a {
public function g(): static { return $this; }
}
class b extends a {}
class c {
public function a(): a { return (new a)->g(); }
public function b(): a&b { return (new b)->g(); }
}
',
'8.1',
['MissingReturnType'],
false,
true,
],
'ArrowFunction' => [
'<?php
fn () => 0;
',
'<?php
fn (): int => 0;
',
'8.0',
['MissingClosureReturnType'],
false,
true,
],
];
}
}