|
48 | 48 | use PHPStan\Type\Accessory\AccessoryArrayListType; |
49 | 49 | use PHPStan\Type\Accessory\HasOffsetValueType; |
50 | 50 | use PHPStan\Type\Accessory\NonEmptyArrayType; |
| 51 | +use PHPStan\Type\ArrayType; |
51 | 52 | use PHPStan\Type\Constant\ConstantArrayType; |
52 | 53 | use PHPStan\Type\Constant\ConstantIntegerType; |
53 | 54 | use PHPStan\Type\Constant\ConstantStringType; |
|
60 | 61 | use PHPStan\Type\Type; |
61 | 62 | use PHPStan\Type\TypeCombinator; |
62 | 63 | use PHPStan\Type\TypeUtils; |
| 64 | +use PHPStan\Type\UnionType; |
63 | 65 | use TypeError; |
64 | 66 | use function array_key_last; |
65 | 67 | use function array_merge; |
@@ -281,6 +283,13 @@ public function processAssignVar( |
281 | 283 | $conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $identicalSpecifiedTypes, $falseyType); |
282 | 284 | } |
283 | 285 |
|
| 286 | + $conditionalExpressions = $this->processArrayValueExtractionForConditionalExpressions( |
| 287 | + $scope, |
| 288 | + $var->name, |
| 289 | + $conditionalExpressions, |
| 290 | + $assignedExpr, |
| 291 | + ); |
| 292 | + |
284 | 293 | $nodeScopeResolver->callNodeCallback($nodeCallback, new VariableAssignNode($var, $assignedExpr), $scopeBeforeAssignEval, $storage); |
285 | 294 | $scope = $scope->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr), TrinaryLogic::createYes()); |
286 | 295 | foreach ($conditionalExpressions as $exprString => $holders) { |
@@ -1076,4 +1085,69 @@ private function isSameVariable(Expr $a, Expr $b): bool |
1076 | 1085 | return false; |
1077 | 1086 | } |
1078 | 1087 |
|
| 1088 | + /** |
| 1089 | + * @param array<string, ConditionalExpressionHolder[]> $conditionalExpressions |
| 1090 | + * @return array<string, ConditionalExpressionHolder[]> |
| 1091 | + */ |
| 1092 | + private function processArrayValueExtractionForConditionalExpressions( |
| 1093 | + Scope $scope, |
| 1094 | + string $variableName, |
| 1095 | + array $conditionalExpressions, |
| 1096 | + Expr $assignedExpr, |
| 1097 | + ): array |
| 1098 | + { |
| 1099 | + if ( |
| 1100 | + !$assignedExpr instanceof Expr\FuncCall |
| 1101 | + || !$assignedExpr->name instanceof Name |
| 1102 | + || !in_array($assignedExpr->name->toLowerString(), ['reset', 'current', 'end'], true) |
| 1103 | + || count($assignedExpr->getArgs()) < 1 |
| 1104 | + ) { |
| 1105 | + return $conditionalExpressions; |
| 1106 | + } |
| 1107 | + |
| 1108 | + $arrayArg = $assignedExpr->getArgs()[0]->value; |
| 1109 | + if (!$arrayArg instanceof Variable || !is_string($arrayArg->name)) { |
| 1110 | + return $conditionalExpressions; |
| 1111 | + } |
| 1112 | + |
| 1113 | + $arrayArgType = $scope->getType($arrayArg); |
| 1114 | + if (!$arrayArgType->isArray()->yes()) { |
| 1115 | + return $conditionalExpressions; |
| 1116 | + } |
| 1117 | + |
| 1118 | + $valueType = $arrayArgType->getIterableValueType(); |
| 1119 | + if (!$valueType instanceof UnionType) { |
| 1120 | + return $conditionalExpressions; |
| 1121 | + } |
| 1122 | + |
| 1123 | + $valueTypeMembers = $valueType->getTypes(); |
| 1124 | + if (count($valueTypeMembers) < 2) { |
| 1125 | + return $conditionalExpressions; |
| 1126 | + } |
| 1127 | + |
| 1128 | + $arrayExprString = '$' . $arrayArg->name; |
| 1129 | + $keyType = $arrayArgType->getIterableKeyType(); |
| 1130 | + |
| 1131 | + foreach ($valueTypeMembers as $memberType) { |
| 1132 | + $narrowedArrayType = TypeCombinator::intersect( |
| 1133 | + $arrayArgType, |
| 1134 | + new ArrayType($keyType, $memberType), |
| 1135 | + ); |
| 1136 | + |
| 1137 | + $holder = new ConditionalExpressionHolder( |
| 1138 | + ['$' . $variableName => ExpressionTypeHolder::createYes( |
| 1139 | + new Variable($variableName), |
| 1140 | + $memberType, |
| 1141 | + )], |
| 1142 | + ExpressionTypeHolder::createYes( |
| 1143 | + $arrayArg, |
| 1144 | + $narrowedArrayType, |
| 1145 | + ), |
| 1146 | + ); |
| 1147 | + $conditionalExpressions[$arrayExprString][$holder->getKey()] = $holder; |
| 1148 | + } |
| 1149 | + |
| 1150 | + return $conditionalExpressions; |
| 1151 | + } |
| 1152 | + |
1079 | 1153 | } |
0 commit comments