Skip to content

Commit aeb651a

Browse files
Handle default value in phpstan-assert (#4226)
1 parent ce9380e commit aeb651a

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use PhpParser\Node\Name;
2222
use PHPStan\DependencyInjection\AutowiredService;
2323
use PHPStan\Node\Expr\AlwaysRememberedExpr;
24+
use PHPStan\Node\Expr\TypeExpr;
2425
use PHPStan\Node\IssetExpr;
2526
use PHPStan\Node\Printer\ExprPrinter;
2627
use PHPStan\Php\PhpVersion;
@@ -1451,6 +1452,14 @@ private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\Cal
14511452

14521453
$argsMap[$paramName][] = $arg->value;
14531454
}
1455+
foreach ($parameters as $parameter) {
1456+
$name = $parameter->getName();
1457+
$defaultValue = $parameter->getDefaultValue();
1458+
if (isset($argsMap[$name]) || $defaultValue === null) {
1459+
continue;
1460+
}
1461+
$argsMap[$name][] = new TypeExpr($defaultValue);
1462+
}
14541463

14551464
if ($call instanceof MethodCall) {
14561465
$argsMap['this'] = [$call->var];
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<?php // lint >= 8.0
2+
3+
declare(strict_types=1);
4+
5+
namespace Bug9435;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
function x(): mixed
10+
{
11+
return null;
12+
}
13+
14+
/** @phpstan-assert ($allow_null is true ? string|null : string) $input */
15+
function trueCheck(mixed $input, bool $allow_null = false): void
16+
{
17+
}
18+
19+
$a = x();
20+
trueCheck($a);
21+
assertType('string', $a); // incorrect: should be string but is string|null
22+
23+
$a = x();
24+
trueCheck($a, false);
25+
assertType('string', $a); // correct (string)
26+
27+
$a = x();
28+
trueCheck($a, allow_null: false);
29+
assertType('string', $a); // correct (string)
30+
31+
$a = x();
32+
trueCheck(allow_null: false, input: $a);
33+
assertType('string', $a); // correct (string)
34+
35+
$a = x();
36+
trueCheck($a, true);
37+
assertType('string|null', $a); // correct (string|null)
38+
39+
$a = x();
40+
trueCheck($a, allow_null: true);
41+
assertType('string|null', $a); // correct (string|null)
42+
43+
$a = x();
44+
trueCheck(allow_null: true, input: $a);
45+
assertType('string|null', $a); // correct (string|null)
46+
47+
/** @phpstan-assert ($allow_null is false ? string : string|null) $input */
48+
function falseCheck(mixed $input, bool $allow_null = false): void
49+
{
50+
}
51+
52+
$a = x();
53+
falseCheck($a);
54+
assertType('string', $a); // incorrect: should be string but is string|null
55+
56+
$a = x();
57+
falseCheck($a, false);
58+
assertType('string', $a); // correct (string)
59+
60+
$a = x();
61+
falseCheck($a, allow_null: false);
62+
assertType('string', $a); // correct (string)
63+
64+
$a = x();
65+
falseCheck(allow_null: false, input: $a);
66+
assertType('string', $a); // correct (string|null)
67+
68+
$a = x();
69+
falseCheck($a, true);
70+
assertType('string|null', $a); // correct (string|null)
71+
72+
$a = x();
73+
falseCheck($a, allow_null: true);
74+
assertType('string|null', $a); // correct (string|null)
75+
76+
$a = x();
77+
falseCheck(allow_null: true, input: $a);
78+
assertType('string|null', $a); // correct (string|null)
79+
80+
/** @phpstan-assert ($allow_null is not true ? string : string|null) $input */
81+
function notTrueCheck(mixed $input, bool $allow_null = false): void
82+
{
83+
}
84+
85+
$a = x();
86+
notTrueCheck($a);
87+
assertType('string', $a); // incorrect: should be string but is string|null
88+
89+
$a = x();
90+
notTrueCheck($a, false);
91+
assertType('string', $a); // correct (string)
92+
93+
$a = x();
94+
notTrueCheck($a, allow_null: false);
95+
assertType('string', $a); // correct (string)
96+
97+
$a = x();
98+
notTrueCheck(allow_null: false, input: $a);
99+
assertType('string', $a); // correct (string|null)
100+
101+
$a = x();
102+
notTrueCheck($a, true);
103+
assertType('string|null', $a); // correct (string|null)
104+
105+
$a = x();
106+
notTrueCheck($a, allow_null: true);
107+
assertType('string|null', $a); // correct (string|null)
108+
109+
$a = x();
110+
notTrueCheck(allow_null: true, input: $a);
111+
assertType('string|null', $a); // correct (string|null)
112+
113+
/** @phpstan-assert ($allow_null is not false ? string|null : string) $input */
114+
function notFalseCheck(mixed $input, bool $allow_null = false): void
115+
{
116+
}
117+
118+
$a = x();
119+
notFalseCheck($a);
120+
assertType('string', $a); // incorrect: should be string but is string|null
121+
122+
$a = x();
123+
notFalseCheck($a, false);
124+
assertType('string', $a); // correct (string)
125+
126+
$a = x();
127+
notFalseCheck($a, allow_null: false);
128+
assertType('string', $a); // correct (string)
129+
130+
$a = x();
131+
notFalseCheck(allow_null: false, input: $a);
132+
assertType('string', $a); // correct (string|null)
133+
134+
$a = x();
135+
notFalseCheck($a, true);
136+
assertType('string|null', $a); // correct (string|null)
137+
138+
$a = x();
139+
notFalseCheck($a, allow_null: true);
140+
assertType('string|null', $a); // correct (string|null)
141+
142+
$a = x();
143+
notFalseCheck(allow_null: true, input: $a);
144+
assertType('string|null', $a); // correct (string|null)
145+
146+
/** @phpstan-assert ($allow_null is false ? string : string|null) $input */
147+
function checkWithVariadics(mixed $input, bool $allow_null = false, ...$more): void
148+
{
149+
}
150+
151+
$a = x();
152+
checkWithVariadics($a);
153+
assertType('string', $a); // incorrect: should be string but is string|null
154+
155+
$a = x();
156+
checkWithVariadics($a, false);
157+
assertType('string', $a); // correct (string)
158+
159+
$a = x();
160+
checkWithVariadics($a, allow_null: false);
161+
assertType('string', $a); // correct (string)
162+
163+
$a = x();
164+
checkWithVariadics(allow_null: false, input: $a);
165+
assertType('string', $a); // correct (string)
166+
167+
$a = x();
168+
checkWithVariadics($a, true);
169+
assertType('string|null', $a); // correct (string|null)
170+
171+
$a = x();
172+
checkWithVariadics($a, allow_null: true);
173+
assertType('string|null', $a); // correct (string|null)
174+
175+
$a = x();
176+
checkWithVariadics(allow_null: true, input: $a);
177+
assertType('string|null', $a); // correct (string|null)

0 commit comments

Comments
 (0)