Repository navigation
Expand file tree
/
Copy pathbug-15228.php
More file actions
109 lines (86 loc) · 1.93 KB
/
Copy pathbug-15228.php
File metadata and controls
109 lines (86 loc) · 1.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?php declare(strict_types = 1);
namespace Bug15228;
use function PHPStan\dumpType;
use function PHPStan\Testing\assertType;
class CoalesceAssignDemo
{
public ?int $a = null;
/** @var list<int>|null */
public $b;
/** @return list<string> */
private function strings(): array
{
return ['x'];
}
// === Symptom 1: false negative below level 7 ===
// Both methods write a string into ?int - a guaranteed TypeError.
public function coalesceInvalid(): void
{
$this->a ??= 'boom'; // (NOT reported at levels 0-6.)
}
public function ifInvalid(): void
{
if (null === $this->a) {
$this->a = 'boom'; // (Reported from level 0. Correct.)
}
}
// === Symptom 2: false positive at level 7+ ===
// Both methods write list<int>, which the property accepts.
public function coalesceValid(): void
{
$this->b = $this->strings(); // (Genuine error, both methods.)
$this->b ??= [1, 2]; // VALID write - reported at 7+ anyway.
}
public function ifValid(): void
{
$this->b = $this->strings(); // (Genuine error, both methods.)
if (null === $this->b) {
$this->b = [1, 2]; // VALID write - correctly not reported.
}
}
}
class Adjacent
{
public static ?int $s = null;
public ?int $a = null;
public int $uninitialized;
public function staticProperty(): void
{
self::$s ??= 'boom';
}
public function neverNull(): void
{
$this->a = 1;
$this->a ??= 'never written';
}
public function maybeUninitialized(): void
{
$this->uninitialized ??= 'boom';
}
public function valid(): void
{
$this->a ??= 5;
self::$s ??= 5;
}
}
class RightSideNarrowing
{
public ?string $q = null;
public function rightSideSeesNullLeftSide(): void
{
$this->q ??= $this->q === null ? 'x' : 1;
}
}
class Offsets
{
/** @var array<string, int> */
public array $m = [];
public function invalid(): void
{
$this->m['k'] ??= 'boom';
}
public function valid(): void
{
$this->m['k'] ??= 5;
}
}