Skip to content

Commit 22ace72

Browse files
committed
Support null templates
1 parent 30f8f1c commit 22ace72

File tree

8 files changed

+30
-47
lines changed

8 files changed

+30
-47
lines changed

src/Rules/Generics/TemplateTypeCheck.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use PHPStan\Type\IterableType;
2929
use PHPStan\Type\KeyOfType;
3030
use PHPStan\Type\MixedType;
31+
use PHPStan\Type\NullType;
3132
use PHPStan\Type\ObjectShapeType;
3233
use PHPStan\Type\ObjectType;
3334
use PHPStan\Type\ObjectWithoutClassType;
@@ -132,6 +133,7 @@ public function check(
132133
&& $boundTypeClass !== GenericObjectType::class
133134
&& $boundTypeClass !== KeyOfType::class
134135
&& $boundTypeClass !== IterableType::class
136+
&& $boundTypeClass !== NullType::class
135137
&& !$boundType instanceof UnionType
136138
&& !$boundType instanceof IntersectionType
137139
&& !$boundType instanceof TemplateType
Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
1-
<?php declare(strict_types = 1);
1+
<?php declare(strict_types = 1); // lint >= 8.0
22

33
namespace Bug12894;
44

5+
use Closure;
6+
57
/**
68
* @template TValue of object|null
79
*/
8-
interface Dependency {
10+
interface Dependency
11+
{
12+
913
/**
1014
* @return TValue
1115
*/
1216
public function __invoke(): object|null;
17+
1318
}
1419

15-
interface DependencyResolver {
20+
interface DependencyResolver
21+
{
22+
1623
/**
1724
* @template V of object|null
1825
* @template D of Dependency<V>
@@ -22,25 +29,23 @@ interface DependencyResolver {
2229
* @return V
2330
*/
2431
public function resolve(Dependency $dependency): object|null;
32+
2533
}
2634

27-
/**
28-
* @internal
29-
*/
30-
class Resolver implements DependencyResolver {
31-
public function __construct(
32-
/**
33-
* @var Closure(object|null): void
34-
*/
35-
protected readonly Closure $run,
36-
) {
37-
// empty
38-
}
35+
class Resolver implements DependencyResolver
36+
{
37+
/**
38+
* @var Closure(object|null): void
39+
*/
40+
protected Closure $run;
3941

4042
public function resolve(Dependency $dependency): object|null {
4143
$resolved = $dependency();
44+
\PHPStan\Testing\assertType('V of object|null (method Bug12894\DependencyResolver::resolve(), argument)', $resolved);
4245
$result = is_object($resolved) ? 1 : 2;
46+
\PHPStan\Testing\assertType('V of object (method Bug12894\DependencyResolver::resolve(), argument)|V of null (method Bug12894\DependencyResolver::resolve(), argument)', $resolved);
4347
($this->run)($resolved);
4448
return $resolved;
4549
}
50+
4651
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
function a(?int $b): ?int
1111
{
1212
if ($b === null) {
13+
\PHPStan\Testing\assertType('T of null (function Bug12989\a(), argument)', $b);
1314
return $b;
1415
}
1516
return $b;
1617
}
17-

tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ public function testRule(): void
5656
'PHPDoc tag @template T for function FunctionTemplateType\resourceBound() with bound type resource is not supported.',
5757
50,
5858
],
59-
[
60-
'PHPDoc tag @template T for function FunctionTemplateType\nullNotSupported() with bound type null is not supported.',
61-
68,
62-
],
6359
[
6460
'Call-site variance of covariant int in generic type FunctionTemplateType\GenericCovariant<covariant int> in PHPDoc tag @template U is redundant, template type T of class FunctionTemplateType\GenericCovariant has the same variance.',
6561
94,

tests/PHPStan/Rules/Generics/data/function-template.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function nakano()
6565
}
6666

6767
/** @template T of null */
68-
function nullNotSupported()
68+
function nullSupported()
6969
{
7070

7171
}

tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,6 @@ public function testGenericCallables(): void
320320
'PHPDoc tag @param for parameter $invalidBoundType template T of Closure<T of GenericCallablesIncompatible\Invalid>(T): T has invalid bound type GenericCallablesIncompatible\Invalid.',
321321
25,
322322
],
323-
[
324-
'PHPDoc tag @param for parameter $notSupported template T of Closure<T of null>(T): T with bound type null is not supported.',
325-
32,
326-
],
327323
[
328324
'PHPDoc tag @param for parameter $shadows template T of Closure<T of mixed>(T): T shadows @template T for function GenericCallablesIncompatible\testShadowFunction.',
329325
40,
@@ -360,10 +356,6 @@ public function testGenericCallables(): void
360356
'PHPDoc tag @return template T of Closure<T of GenericCallablesIncompatible\Invalid>(T): T has invalid bound type GenericCallablesIncompatible\Invalid.',
361357
90,
362358
],
363-
[
364-
'PHPDoc tag @return template T of Closure<T of null>(T): T with bound type null is not supported.',
365-
97,
366-
],
367359
[
368360
'PHPDoc tag @return template T of Closure<T of mixed>(T): T shadows @template T for function GenericCallablesIncompatible\testShadowFunctionReturn.',
369361
105,
@@ -380,10 +372,6 @@ public function testGenericCallables(): void
380372
'PHPDoc tag @param for parameter $invalidBoundType template T of Closure<T of GenericCallablesIncompatible\Invalid>(T): T has invalid bound type GenericCallablesIncompatible\Invalid.',
381373
131,
382374
],
383-
[
384-
'PHPDoc tag @param for parameter $notSupported template T of Closure<T of null>(T): T with bound type null is not supported.',
385-
138,
386-
],
387375
[
388376
'PHPDoc tag @return template of Closure<stdClass of mixed>(stdClass): stdClass cannot have existing class stdClass as its name.',
389377
145,
@@ -396,10 +384,6 @@ public function testGenericCallables(): void
396384
'PHPDoc tag @return template T of Closure<T of GenericCallablesIncompatible\Invalid>(T): T has invalid bound type GenericCallablesIncompatible\Invalid.',
397385
159,
398386
],
399-
[
400-
'PHPDoc tag @return template T of Closure<T of null>(T): T with bound type null is not supported.',
401-
166,
402-
],
403387
[
404388
'PHPDoc tag @param-out for parameter $existingClass template T of Closure<T of mixed>(T): T shadows @template T for function GenericCallablesIncompatible\shadowsParamOut.',
405389
175,

tests/PHPStan/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,6 @@ public function testGenericCallables(): void
186186
'PHPDoc tag @var template of callable<TypeAlias of mixed>(TypeAlias): TypeAlias cannot have existing type alias TypeAlias as its name.',
187187
26,
188188
],
189-
[
190-
'PHPDoc tag @var template TNull of callable<TNull of null>(TNull): TNull with bound type null is not supported.',
191-
31,
192-
],
193189
[
194190
'PHPDoc tag @var template TInvalid of callable<TInvalid of GenericCallableProperties\Invalid>(TInvalid): TInvalid has invalid bound type GenericCallableProperties\Invalid.',
195191
36,

tests/PHPStan/Rules/PhpDoc/data/generic-callables-incompatible.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ function invalidBoundType(Closure $invalidBoundType): void
2727
}
2828

2929
/**
30-
* @param Closure<T of null>(T $val): T $notSupported
30+
* @param Closure<T of null>(T $val): T $closure
3131
*/
32-
function notSupported(Closure $notSupported): void
32+
function testNull(Closure $closure): void
3333
{
3434
}
3535

@@ -94,7 +94,7 @@ function invalidBoundTypeReturn(): Closure
9494
/**
9595
* @return Closure<T of null>(T $val): T
9696
*/
97-
function notSupportedReturn(): Closure
97+
function nullReturn(): Closure
9898
{
9999
}
100100

@@ -133,9 +133,9 @@ public function invalidBoundType(Closure $invalidBoundType): void
133133
}
134134

135135
/**
136-
* @param Closure<T of null>(T $val): T $notSupported
136+
* @param Closure<T of null>(T $val): T $closure
137137
*/
138-
public function notSupported(Closure $notSupported): void
138+
public function nullType(Closure $closure): void
139139
{
140140
}
141141

@@ -163,7 +163,7 @@ public function invalidBoundTypeReturn(): Closure
163163
/**
164164
* @return Closure<T of null>(T $val): T
165165
*/
166-
public function notSupportedReturn(): Closure
166+
public function nullReturn(): Closure
167167
{
168168
}
169169
}

0 commit comments

Comments
 (0)