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