@@ -741,36 +741,12 @@ public function unsetOffset(Type $offsetType): Type
741741 $ k ++;
742742 }
743743
744- $ newIsList = TrinaryLogic::createNo ();
745- // We're unsetting something that might not be on the array,
746- // so it might still be a list (with PHPStan definition)
747- // because the nextAutoIndexes will not change.
748- if (!$ this ->isList ->no () && in_array ($ i , $ this ->optionalKeys , true )) {
749- $ preserveIsList = true ;
750- $ isListOnlyIfKeysAreOptional = false ;
751- foreach ($ newKeyTypes as $ k2 => $ newKeyType2 ) {
752- if (!$ newKeyType2 instanceof ConstantIntegerType || $ newKeyType2 ->getValue () !== $ k2 ) {
753- // We found a non-optional key that implies that the array is never a list.
754- if (!in_array ($ k2 , $ newOptionalKeys , true )) {
755- $ preserveIsList = false ;
756- break ;
757- }
758-
759- // The array can still be a list if all the following keys are also optional.
760- $ isListOnlyIfKeysAreOptional = true ;
761- continue ;
762- }
763-
764- if ($ isListOnlyIfKeysAreOptional && !in_array ($ k2 , $ newOptionalKeys , true )) {
765- $ preserveIsList = false ;
766- break ;
767- }
768- }
769-
770- if ($ preserveIsList ) {
771- $ newIsList = TrinaryLogic::createMaybe ();
772- }
773- }
744+ $ newIsList = $ this ->isListAfterUnset (
745+ $ newKeyTypes ,
746+ $ newOptionalKeys ,
747+ $ this ->isList ,
748+ in_array ($ i , $ this ->optionalKeys , true ),
749+ );
774750
775751 return new self ($ newKeyTypes , $ newValueTypes , $ this ->nextAutoIndexes , $ newOptionalKeys , $ newIsList );
776752 }
@@ -801,21 +777,64 @@ public function unsetOffset(Type $offsetType): Type
801777 }
802778 }
803779
804- return new self ($ this ->keyTypes , $ this ->valueTypes , $ this ->nextAutoIndexes , $ optionalKeys , TrinaryLogic::createNo ());
780+ $ newIsList = $ this ->isListAfterUnset (
781+ $ this ->keyTypes ,
782+ $ optionalKeys ,
783+ $ this ->isList ,
784+ count ($ optionalKeys ) === count ($ this ->optionalKeys ),
785+ );
786+
787+ return new self ($ this ->keyTypes , $ this ->valueTypes , $ this ->nextAutoIndexes , $ optionalKeys , $ newIsList );
805788 }
806789
807790 $ optionalKeys = $ this ->optionalKeys ;
808- $ isList = $ this ->isList ;
809791 foreach ($ this ->keyTypes as $ i => $ keyType ) {
810792 if (!$ offsetType ->isSuperTypeOf ($ keyType )->yes ()) {
811793 continue ;
812794 }
813795 $ optionalKeys [] = $ i ;
814- $ isList = TrinaryLogic::createNo ();
815796 }
816797 $ optionalKeys = array_values (array_unique ($ optionalKeys ));
817798
818- return new self ($ this ->keyTypes , $ this ->valueTypes , $ this ->nextAutoIndexes , $ optionalKeys , $ isList );
799+ $ newIsList = $ this ->isListAfterUnset (
800+ $ this ->keyTypes ,
801+ $ optionalKeys ,
802+ $ this ->isList ,
803+ count ($ optionalKeys ) === count ($ this ->optionalKeys ),
804+ );
805+
806+ return new self ($ this ->keyTypes , $ this ->valueTypes , $ this ->nextAutoIndexes , $ optionalKeys , $ newIsList );
807+ }
808+
809+ /**
810+ * If we're unsetting something that might not be on the array, it might still be a list (with PHPStan definition)
811+ * because the nextAutoIndexes will not change.
812+ */
813+ private function isListAfterUnset (array $ newKeyTypes , array $ newOptionalKeys , TrinaryLogic $ arrayIsList , bool $ unsetOptionalKey ): TrinaryLogic
814+ {
815+ if (!$ unsetOptionalKey || $ arrayIsList ->no ()) {
816+ return TrinaryLogic::createNo ();
817+ }
818+
819+ $ isListOnlyIfKeysAreOptional = false ;
820+ foreach ($ newKeyTypes as $ k2 => $ newKeyType2 ) {
821+ if (!$ newKeyType2 instanceof ConstantIntegerType || $ newKeyType2 ->getValue () !== $ k2 ) {
822+ // We found a non-optional key that implies that the array is never a list.
823+ if (!in_array ($ k2 , $ newOptionalKeys , true )) {
824+ return TrinaryLogic::createNo ();
825+ }
826+
827+ // The array can still be a list if all the following keys are also optional.
828+ $ isListOnlyIfKeysAreOptional = true ;
829+ continue ;
830+ }
831+
832+ if ($ isListOnlyIfKeysAreOptional && !in_array ($ k2 , $ newOptionalKeys , true )) {
833+ return TrinaryLogic::createNo ();
834+ }
835+ }
836+
837+ return TrinaryLogic::createMaybe ();
819838 }
820839
821840 public function chunkArray (Type $ lengthType , TrinaryLogic $ preserveKeys ): Type
0 commit comments