@@ -110,11 +110,16 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
110110 if ($ offsetType === null ) {
111111 $ newAutoIndexes = $ optional ? $ this ->nextAutoIndexes : [];
112112 $ hasOptional = false ;
113+ $ existingMaxIndex = -1 ;
113114 foreach ($ this ->keyTypes as $ i => $ keyType ) {
114115 if (!$ keyType instanceof ConstantIntegerType) {
115116 continue ;
116117 }
117118
119+ if ($ keyType ->getValue () > $ existingMaxIndex ) {
120+ $ existingMaxIndex = $ keyType ->getValue ();
121+ }
122+
118123 if (!in_array ($ keyType ->getValue (), $ this ->nextAutoIndexes , true )) {
119124 continue ;
120125 }
@@ -153,6 +158,10 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
153158 $ this ->optionalKeys [] = count ($ this ->keyTypes ) - 1 ;
154159 }
155160
161+ if ($ max < 0 || $ max > $ existingMaxIndex + 1 ) {
162+ $ this ->isList = $ this ->isList ->and ($ optional || $ hasOptional ? TrinaryLogic::createMaybe () : TrinaryLogic::createNo ());
163+ }
164+
156165 if (
157166 !$ this ->disableArrayDegradation
158167 && count ($ this ->keyTypes ) > self ::ARRAY_COUNT_LIMIT
@@ -199,12 +208,14 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
199208 $ offsetValue = $ offsetType ->getValue ();
200209 if ($ offsetValue >= 0 ) {
201210 if ($ offsetValue > $ min ) {
202- if ($ offsetValue <= $ max ) {
211+ if ($ offsetValue <= $ max || $ optional ) {
203212 $ this ->isList = $ this ->isList ->and (TrinaryLogic::createMaybe ());
204213 } else {
205214 $ this ->isList = TrinaryLogic::createNo ();
206215 }
207216 }
217+ } elseif ($ optional ) {
218+ $ this ->isList = $ this ->isList ->and (TrinaryLogic::createMaybe ());
208219 } else {
209220 $ this ->isList = TrinaryLogic::createNo ();
210221 }
@@ -221,6 +232,8 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
221232 $ this ->nextAutoIndexes [] = $ newAutoIndex ;
222233 }
223234 }
235+ } elseif ($ optional ) {
236+ $ this ->isList = $ this ->isList ->and (TrinaryLogic::createMaybe ());
224237 } else {
225238 $ this ->isList = TrinaryLogic::createNo ();
226239 }
@@ -285,11 +298,17 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
285298 }
286299 }
287300
288- $ this ->isList = TrinaryLogic::createNo ();
301+ if ($ optional ) {
302+ $ this ->isList = $ this ->isList ->and (TrinaryLogic::createMaybe ());
303+ } else {
304+ $ this ->isList = TrinaryLogic::createNo ();
305+ }
289306 }
290307
291308 if ($ offsetType === null ) {
292309 $ offsetType = TypeCombinator::union (...array_map (static fn (int $ index ) => new ConstantIntegerType ($ index ), $ this ->nextAutoIndexes ));
310+ } elseif ($ optional ) {
311+ $ this ->isList = $ this ->isList ->and (TrinaryLogic::createMaybe ());
293312 } else {
294313 $ this ->isList = TrinaryLogic::createNo ();
295314 }
0 commit comments