Skip to content

Commit 04d0e03

Browse files
authored
Error on offset assignment to specialized strings
1 parent ad32861 commit 04d0e03

7 files changed

+124
-0
lines changed

src/Type/Accessory/AccessoryLiteralStringType.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ public function getOffsetValueType(Type $offsetType): Type
153153

154154
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
155155
{
156+
$stringOffset = (new StringType())->setOffsetValueType($offsetType, $valueType, $unionValues);
157+
158+
if ($stringOffset instanceof ErrorType) {
159+
return $stringOffset;
160+
}
161+
156162
if ($valueType->isLiteralString()->yes()) {
157163
return $this;
158164
}

src/Type/Accessory/AccessoryNonEmptyStringType.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ public function getOffsetValueType(Type $offsetType): Type
159159

160160
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
161161
{
162+
$stringOffset = (new StringType())->setOffsetValueType($offsetType, $valueType, $unionValues);
163+
164+
if ($stringOffset instanceof ErrorType) {
165+
return $stringOffset;
166+
}
167+
162168
return $this;
163169
}
164170

src/Type/Accessory/AccessoryNonFalsyStringType.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ public function getOffsetValueType(Type $offsetType): Type
155155

156156
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
157157
{
158+
$stringOffset = (new StringType())->setOffsetValueType($offsetType, $valueType, $unionValues);
159+
160+
if ($stringOffset instanceof ErrorType) {
161+
return $stringOffset;
162+
}
163+
158164
if ($valueType->isNonFalsyString()->yes()) {
159165
return $this;
160166
}

src/Type/Accessory/AccessoryNumericStringType.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ public function getOffsetValueType(Type $offsetType): Type
158158

159159
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
160160
{
161+
$stringOffset = (new StringType())->setOffsetValueType($offsetType, $valueType, $unionValues);
162+
163+
if ($stringOffset instanceof ErrorType) {
164+
return $stringOffset;
165+
}
166+
161167
return $this;
162168
}
163169

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,4 +864,18 @@ public function testBug10997(): void
864864
]);
865865
}
866866

867+
public function testBug11572(): void
868+
{
869+
$this->analyse([__DIR__ . '/data/bug-11572.php'], [
870+
[
871+
'Cannot access an offset on int.',
872+
45,
873+
],
874+
[
875+
'Cannot access an offset on int<3, 4>.',
876+
46,
877+
],
878+
]);
879+
}
880+
867881
}

tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,43 @@ public function testBug8015(): void
156156
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-8015.php'], []);
157157
}
158158

159+
public function testBug11572(): void
160+
{
161+
$this->checkUnionTypes = true;
162+
$this->analyse([__DIR__ . '/data/bug-11572.php'], [
163+
[
164+
'Cannot assign new offset to string.',
165+
15,
166+
],
167+
[
168+
'Cannot assign new offset to string.',
169+
16,
170+
],
171+
[
172+
'Cannot assign new offset to string.',
173+
17,
174+
],
175+
[
176+
'Cannot assign new offset to string.',
177+
18,
178+
],
179+
[
180+
'Cannot assign new offset to string.',
181+
19,
182+
],
183+
[
184+
'Cannot assign new offset to string.',
185+
20,
186+
],
187+
[
188+
'Cannot assign new offset to string.',
189+
24,
190+
],
191+
[
192+
'Cannot assign new offset to string.',
193+
36,
194+
],
195+
]);
196+
}
197+
159198
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace bug11572;
4+
5+
/**
6+
* @param string $s
7+
* @param numeric-string $numericS
8+
* @param literal-string $literalS
9+
* @param non-empty-string $nonEmptyS
10+
* @param non-falsy-string $nonFalsyS
11+
* @param non-falsy-string&literal-string $intersectedS
12+
*/
13+
function doFoo($s, $numericS, $literalS, $nonEmptyS, $nonFalsyS, $intersectedS): void
14+
{
15+
$s[] = 'foo';
16+
$numericS[] = 'foo';
17+
$literalS[] = 'foo';
18+
$nonEmptyS[] = 'foo';
19+
$nonFalsyS[] = 'foo';
20+
$intersectedS[] = 'foo';
21+
}
22+
23+
$string = returnString() . ' bar';
24+
$string[] = 'foo';
25+
26+
function returnString(): string
27+
{
28+
return 'baz';
29+
}
30+
31+
class X {
32+
const XY ='ABC';
33+
34+
function doFoo() {
35+
$s = X::XY;
36+
$s[] = 'foo';
37+
}
38+
}
39+
40+
/**
41+
* @param int<3,4> $range
42+
*/
43+
function doInt(int $i, $range): void
44+
{
45+
$i[] = 1;
46+
$range[] = 1;
47+
}

0 commit comments

Comments
 (0)