|
24 | 24 | use PHPStan\Node\LiteralArrayNode; |
25 | 25 | use PHPStan\Reflection\InitializerExprTypeResolver; |
26 | 26 | use PHPStan\Type\CallableType; |
| 27 | +use PHPStan\Type\Constant\ConstantIntegerType; |
27 | 28 | use PHPStan\Type\Type; |
28 | 29 | use PHPStan\Type\TypeCombinator; |
29 | 30 | use function array_merge; |
@@ -72,27 +73,41 @@ public function resolveType(MutatingScope $scope, Expr $expr): Type |
72 | 73 | return $type; |
73 | 74 | } |
74 | 75 |
|
75 | | - public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Expr $expr, MutatingScope $scope, ExpressionResultStorage $storage, callable $nodeCallback, ExpressionContext $context): ExpressionResult |
| 76 | + public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Expr $expr, MutatingScope $scope, ExpressionResultStorage $storage, callable $nodeCallback, ExpressionContext $context, ?Type $overriddenType): ExpressionResult |
76 | 77 | { |
77 | 78 | $beforeScope = $scope; |
78 | 79 | $itemNodes = []; |
79 | 80 | $hasYield = false; |
80 | 81 | $throwPoints = []; |
81 | 82 | $impurePoints = []; |
82 | 83 | $isAlwaysTerminating = false; |
| 84 | + $nextAutoIndex = 0; |
83 | 85 | foreach ($expr->items as $arrayItem) { |
84 | 86 | $itemNodes[] = new LiteralArrayItem($scope, $arrayItem); |
85 | 87 | $nodeScopeResolver->callNodeCallback($nodeCallback, $arrayItem, $scope, $storage); |
| 88 | + $keyType = new ConstantIntegerType($nextAutoIndex); |
86 | 89 | if ($arrayItem->key !== null) { |
87 | | - $keyResult = $nodeScopeResolver->processExprNode($stmt, $arrayItem->key, $scope, $storage, $nodeCallback, $context->enterDeep()); |
| 90 | + $keyType = $scope->getType($arrayItem->key); |
| 91 | + $keyResult = $nodeScopeResolver->processExprNode($stmt, $arrayItem->key, $scope, $storage, $nodeCallback, $context->enterDeep(), null); |
88 | 92 | $hasYield = $hasYield || $keyResult->hasYield(); |
89 | 93 | $throwPoints = array_merge($throwPoints, $keyResult->getThrowPoints()); |
90 | 94 | $impurePoints = array_merge($impurePoints, $keyResult->getImpurePoints()); |
91 | 95 | $isAlwaysTerminating = $isAlwaysTerminating || $keyResult->isAlwaysTerminating(); |
92 | 96 | $scope = $keyResult->getScope(); |
93 | 97 | } |
94 | 98 |
|
95 | | - $valueResult = $nodeScopeResolver->processExprNode($stmt, $arrayItem->value, $scope, $storage, $nodeCallback, $context->enterDeep()); |
| 99 | + $overriddenValueType = null; |
| 100 | + if ($overriddenType !== null && $overriddenType->hasOffsetValueType($keyType)->yes()) { |
| 101 | + $overriddenValueType = $overriddenType->getOffsetValueType($keyType); |
| 102 | + } |
| 103 | + |
| 104 | + if ($arrayItem->key === null) { |
| 105 | + $nextAutoIndex++; |
| 106 | + } elseif ($keyType instanceof ConstantIntegerType) { |
| 107 | + $nextAutoIndex = $keyType->getValue() + 1; |
| 108 | + } |
| 109 | + |
| 110 | + $valueResult = $nodeScopeResolver->processExprNode($stmt, $arrayItem->value, $scope, $storage, $nodeCallback, $context->enterDeep(), $overriddenValueType); |
96 | 111 | $hasYield = $hasYield || $valueResult->hasYield(); |
97 | 112 | $throwPoints = array_merge($throwPoints, $valueResult->getThrowPoints()); |
98 | 113 | $impurePoints = array_merge($impurePoints, $valueResult->getImpurePoints()); |
|
0 commit comments