Skip to content

Commit 62b2683

Browse files
committed
Merge remote-tracking branch 'origin/1.12.x' into 2.0.x
2 parents f9e84e0 + 0b925a9 commit 62b2683

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

src/Type/IntersectionType.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,14 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni
777777
);
778778
});
779779
}
780-
return $this->intersectTypes(static fn (Type $type): Type => $type->setOffsetValueType($offsetType, $valueType, $unionValues));
780+
781+
$result = $this->intersectTypes(static fn (Type $type): Type => $type->setOffsetValueType($offsetType, $valueType, $unionValues));
782+
783+
if ($offsetType !== null && $this->isList()->yes() && $this->isIterableAtLeastOnce()->yes() && (new ConstantIntegerType(1))->isSuperTypeOf($offsetType)->yes()) {
784+
$result = TypeCombinator::intersect($result, new AccessoryArrayListType());
785+
}
786+
787+
return $result;
781788
}
782789

783790
public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type

tests/PHPStan/Analyser/nsrt/list-type.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,29 @@ public function testUnset(array $list): void
106106
assertType('array<int<0, 1>|int<3, max>, int>', $list);
107107
}
108108

109+
/** @param list<int> $list */
110+
public function testSetOffsetExplicitlyWithoutGap(array $list): void
111+
{
112+
assertType('list<int>', $list);
113+
$list[0] = 17;
114+
assertType('non-empty-list<int>&hasOffsetValue(0, 17)', $list);
115+
$list[1] = 19;
116+
assertType('non-empty-list<int>&hasOffsetValue(0, 17)&hasOffsetValue(1, 19)', $list);
117+
$list[0] = 21;
118+
assertType('non-empty-list<int>&hasOffsetValue(0, 21)&hasOffsetValue(1, 19)', $list);
119+
120+
$list[2] = 23;
121+
assertType('non-empty-array<int<0, max>, int>&hasOffsetValue(0, 21)&hasOffsetValue(1, 19)&hasOffsetValue(2, 23)', $list);
122+
}
123+
124+
/** @param list<int> $list */
125+
public function testSetOffsetExplicitlyWithGap(array $list): void
126+
{
127+
assertType('list<int>', $list);
128+
$list[0] = 17;
129+
assertType('non-empty-list<int>&hasOffsetValue(0, 17)', $list);
130+
$list[2] = 21;
131+
assertType('non-empty-array<int<0, max>, int>&hasOffsetValue(0, 17)&hasOffsetValue(2, 21)', $list);
132+
}
133+
109134
}

tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,4 +676,16 @@ public function testBug4174(): void
676676
$this->analyse([__DIR__ . '/data/bug-4174.php'], []);
677677
}
678678

679+
public function testBug12131(): void
680+
{
681+
$this->checkExplicitMixed = true;
682+
$this->analyse([__DIR__ . '/data/bug-12131.php'], [
683+
[
684+
'Property Bug12131\Test::$array (non-empty-list<int>) does not accept non-empty-array<int<0, max>, int>.',
685+
29,
686+
'non-empty-array<int<0, max>, int> might not be a list.',
687+
],
688+
]);
689+
}
690+
679691
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php declare(strict_types = 1); // lint >= 7.4
2+
3+
namespace Bug12131;
4+
5+
class Test
6+
{
7+
/**
8+
* @var non-empty-list<int>
9+
*/
10+
public array $array;
11+
12+
public function __construct()
13+
{
14+
$this->array = array_fill(0, 10, 1);
15+
}
16+
17+
public function setAtZero(): void
18+
{
19+
$this->array[0] = 1;
20+
}
21+
22+
public function setAtOne(): void
23+
{
24+
$this->array[1] = 1;
25+
}
26+
27+
public function setAtTwo(): void
28+
{
29+
$this->array[2] = 1;
30+
}
31+
}

0 commit comments

Comments
 (0)