Skip to content

Commit 82f1aec

Browse files
herndlmondrejmirtes
authored andcommitted
Add Type::getFirstIterableKeyType() and Type::getLastIterableKeyType()
1 parent 81efe37 commit 82f1aec

15 files changed

+150
-70
lines changed

src/Type/Accessory/AccessoryArrayListType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ public function getIterableKeyType(): Type
152152
return IntegerRangeType::fromInterval(0, null);
153153
}
154154

155+
public function getFirstIterableKeyType(): Type
156+
{
157+
return new ConstantIntegerType(0);
158+
}
159+
160+
public function getLastIterableKeyType(): Type
161+
{
162+
return $this->getIterableKeyType();
163+
}
164+
155165
public function getIterableValueType(): Type
156166
{
157167
return new MixedType();

src/Type/Accessory/NonEmptyArrayType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ public function getIterableKeyType(): Type
141141
return new MixedType();
142142
}
143143

144+
public function getFirstIterableKeyType(): Type
145+
{
146+
return new MixedType();
147+
}
148+
149+
public function getLastIterableKeyType(): Type
150+
{
151+
return new MixedType();
152+
}
153+
144154
public function getIterableValueType(): Type
145155
{
146156
return new MixedType();

src/Type/Accessory/OversizedArrayType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ public function getIterableKeyType(): Type
140140
return new MixedType();
141141
}
142142

143+
public function getFirstIterableKeyType(): Type
144+
{
145+
return new MixedType();
146+
}
147+
148+
public function getLastIterableKeyType(): Type
149+
{
150+
return new MixedType();
151+
}
152+
143153
public function getIterableValueType(): Type
144154
{
145155
return new MixedType();

src/Type/ArrayType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,16 @@ public function getIterableKeyType(): Type
208208
return $keyType;
209209
}
210210

211+
public function getFirstIterableKeyType(): Type
212+
{
213+
return $this->getIterableKeyType();
214+
}
215+
216+
public function getLastIterableKeyType(): Type
217+
{
218+
return $this->getIterableKeyType();
219+
}
220+
211221
public function getIterableValueType(): Type
212222
{
213223
return $this->getItemType();

src/Type/Constant/ConstantArrayType.php

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -227,30 +227,16 @@ public function getKeyTypes(): array
227227
return $this->keyTypes;
228228
}
229229

230+
/** @deprecated Use getFirstIterableKeyType() instead */
230231
public function getFirstKeyType(): Type
231232
{
232-
$keyTypes = [];
233-
foreach ($this->keyTypes as $i => $keyType) {
234-
$keyTypes[] = $keyType;
235-
if (!$this->isOptionalKey($i)) {
236-
break;
237-
}
238-
}
239-
240-
return TypeCombinator::union(...$keyTypes);
233+
return $this->getFirstIterableKeyType();
241234
}
242235

236+
/** @deprecated Use getLastIterableKeyType() instead */
243237
public function getLastKeyType(): Type
244238
{
245-
$keyTypes = [];
246-
for ($i = count($this->keyTypes) - 1; $i >= 0; $i--) {
247-
$keyTypes[] = $this->keyTypes[$i];
248-
if (!$this->isOptionalKey($i)) {
249-
break;
250-
}
251-
}
252-
253-
return TypeCombinator::union(...$keyTypes);
239+
return $this->getLastIterableKeyType();
254240
}
255241

256242
/**
@@ -698,6 +684,32 @@ public function isIterableAtLeastOnce(): TrinaryLogic
698684
return TrinaryLogic::createMaybe();
699685
}
700686

687+
public function getFirstIterableKeyType(): Type
688+
{
689+
$keyTypes = [];
690+
foreach ($this->keyTypes as $i => $keyType) {
691+
$keyTypes[] = $keyType;
692+
if (!$this->isOptionalKey($i)) {
693+
break;
694+
}
695+
}
696+
697+
return TypeCombinator::union(...$keyTypes);
698+
}
699+
700+
public function getLastIterableKeyType(): Type
701+
{
702+
$keyTypes = [];
703+
for ($i = count($this->keyTypes) - 1; $i >= 0; $i--) {
704+
$keyTypes[] = $this->keyTypes[$i];
705+
if (!$this->isOptionalKey($i)) {
706+
break;
707+
}
708+
}
709+
710+
return TypeCombinator::union(...$keyTypes);
711+
}
712+
701713
public function getFirstIterableValueType(): Type
702714
{
703715
$valueTypes = [];

src/Type/IntersectionType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,16 @@ public function getIterableKeyType(): Type
411411
return $this->intersectTypes(static fn (Type $type): Type => $type->getIterableKeyType());
412412
}
413413

414+
public function getFirstIterableKeyType(): Type
415+
{
416+
return $this->intersectTypes(static fn (Type $type): Type => $type->getFirstIterableKeyType());
417+
}
418+
419+
public function getLastIterableKeyType(): Type
420+
{
421+
return $this->intersectTypes(static fn (Type $type): Type => $type->getLastIterableKeyType());
422+
}
423+
414424
public function getIterableValueType(): Type
415425
{
416426
return $this->intersectTypes(static fn (Type $type): Type => $type->getIterableValueType());

src/Type/MixedType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,16 @@ public function getIterableKeyType(): Type
371371
return new self($this->isExplicitMixed);
372372
}
373373

374+
public function getFirstIterableKeyType(): Type
375+
{
376+
return new self($this->isExplicitMixed);
377+
}
378+
379+
public function getLastIterableKeyType(): Type
380+
{
381+
return new self($this->isExplicitMixed);
382+
}
383+
374384
public function getIterableValueType(): Type
375385
{
376386
return new self($this->isExplicitMixed);

src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
use PhpParser\Node\Expr\FuncCall;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Reflection\FunctionReflection;
8-
use PHPStan\Reflection\ParametersAcceptorSelector;
9-
use PHPStan\Type\Constant\ConstantIntegerType;
108
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
119
use PHPStan\Type\NullType;
1210
use PHPStan\Type\Type;
1311
use PHPStan\Type\TypeCombinator;
14-
use function count;
1512

1613
class ArrayKeyFirstDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
1714
{
@@ -21,10 +18,10 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo
2118
return $functionReflection->getName() === 'array_key_first';
2219
}
2320

24-
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
21+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
2522
{
2623
if (!isset($functionCall->getArgs()[0])) {
27-
return ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
24+
return null;
2825
}
2926

3027
$argType = $scope->getType($functionCall->getArgs()[0]->value);
@@ -33,30 +30,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
3330
return new NullType();
3431
}
3532

36-
$constantArrays = $argType->getConstantArrays();
37-
if (count($constantArrays) > 0) {
38-
$keyTypes = [];
39-
foreach ($constantArrays as $constantArray) {
40-
$iterableAtLeastOnce = $constantArray->isIterableAtLeastOnce();
41-
if (!$iterableAtLeastOnce->yes()) {
42-
$keyTypes[] = new NullType();
43-
}
44-
if ($iterableAtLeastOnce->no()) {
45-
continue;
46-
}
47-
48-
$keyTypes[] = $constantArray->getFirstKeyType();
49-
}
50-
51-
return TypeCombinator::union(...$keyTypes);
52-
}
53-
54-
if ($argType->isList()->yes()) {
55-
$keyType = new ConstantIntegerType(0);
56-
} else {
57-
$keyType = $argType->getIterableKeyType();
58-
}
59-
33+
$keyType = $argType->getFirstIterableKeyType();
6034
if ($iterableAtLeastOnce->yes()) {
6135
return $keyType;
6236
}

src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
use PhpParser\Node\Expr\FuncCall;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Reflection\FunctionReflection;
8-
use PHPStan\Reflection\ParametersAcceptorSelector;
98
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
109
use PHPStan\Type\NullType;
1110
use PHPStan\Type\Type;
1211
use PHPStan\Type\TypeCombinator;
13-
use function count;
1412

1513
class ArrayKeyLastDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
1614
{
@@ -20,10 +18,10 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo
2018
return $functionReflection->getName() === 'array_key_last';
2119
}
2220

23-
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
21+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
2422
{
2523
if (!isset($functionCall->getArgs()[0])) {
26-
return ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
24+
return null;
2725
}
2826

2927
$argType = $scope->getType($functionCall->getArgs()[0]->value);
@@ -32,25 +30,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
3230
return new NullType();
3331
}
3432

35-
$constantArrays = $argType->getConstantArrays();
36-
if (count($constantArrays) > 0) {
37-
$keyTypes = [];
38-
foreach ($constantArrays as $constantArray) {
39-
$iterableAtLeastOnce = $constantArray->isIterableAtLeastOnce();
40-
if (!$iterableAtLeastOnce->yes()) {
41-
$keyTypes[] = new NullType();
42-
}
43-
if ($iterableAtLeastOnce->no()) {
44-
continue;
45-
}
46-
47-
$keyTypes[] = $constantArray->getLastKeyType();
48-
}
49-
50-
return TypeCombinator::union(...$keyTypes);
51-
}
52-
53-
$keyType = $argType->getIterableKeyType();
33+
$keyType = $argType->getLastIterableKeyType();
5434
if ($iterableAtLeastOnce->yes()) {
5535
return $keyType;
5636
}

src/Type/StaticType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,16 @@ public function getIterableKeyType(): Type
302302
return $this->getStaticObjectType()->getIterableKeyType();
303303
}
304304

305+
public function getFirstIterableKeyType(): Type
306+
{
307+
return $this->getStaticObjectType()->getFirstIterableKeyType();
308+
}
309+
310+
public function getLastIterableKeyType(): Type
311+
{
312+
return $this->getStaticObjectType()->getLastIterableKeyType();
313+
}
314+
305315
public function getIterableValueType(): Type
306316
{
307317
return $this->getStaticObjectType()->getIterableValueType();

0 commit comments

Comments
 (0)