2929use function array_merge ;
3030use function array_slice ;
3131use function array_splice ;
32- use function array_unique ;
3332use function array_values ;
3433use function count ;
3534use function get_class ;
@@ -714,10 +713,9 @@ private static function processArrayTypes(array $arrayTypes): array
714713 }
715714
716715 if ($ generalArrayOccurred && (!$ overflowed || $ filledArrays > 1 )) {
717- // Do this only for arrays which would be generalized, because this breaks tagged unions.
718- $ singleConstantArray = self ::unionConstantArrayTypesWithSameKeys ($ constantArraysMap );
719- if ($ singleConstantArray !== null ) {
720- return [$ singleConstantArray ];
716+ $ reducedArrayTypes = self ::reduceArrays ($ arrayTypes , false );
717+ if (count ($ reducedArrayTypes ) === 1 ) {
718+ return $ reducedArrayTypes ;
721719 }
722720 $ scopes = [];
723721 $ useTemplateArray = true ;
@@ -751,70 +749,14 @@ private static function processArrayTypes(array $arrayTypes): array
751749 ];
752750 }
753751
754- $ reducedArrayTypes = self ::reduceArrays ($ arrayTypes );
752+ $ reducedArrayTypes = self ::reduceArrays ($ arrayTypes, true );
755753
756754 return array_map (
757755 static fn (Type $ arrayType ) => self ::intersect ($ arrayType , ...$ accessoryTypes ),
758756 self ::optimizeConstantArrays ($ reducedArrayTypes ),
759757 );
760758 }
761759
762- /**
763- * @param non-empty-list<ConstantArrayType[]> $constantArraysMap
764- */
765- private static function unionConstantArrayTypesWithSameKeys (array $ constantArraysMap ): ?ConstantArrayType
766- {
767- $ singleConstantArrayList = [];
768- $ constantArraySizes = [];
769- 770- foreach ($ constantArraysMap as $ constantArrays ) {
771- if (count ($ constantArrays ) !== 1 ) {
772- return null ;
773- }
774- 775- $ singleConstantArrayList [] = $ constantArrays [0 ];
776- $ constantArraySizes [] = count ($ constantArrays [0 ]->getKeyTypes ());
777- }
778- 779- if (count (array_unique ($ constantArraySizes )) !== 1 ) {
780- return null ;
781- }
782- 783- $ finalKeyTypes = $ singleConstantArrayList [0 ]->getKeyTypes ();
784- $ finalValueTypesMap = [];
785- for ($ i = 0 ; $ i < $ constantArraySizes [0 ]; $ i ++) {
786- $ finalValueTypesMap [$ i ] = [$ singleConstantArrayList [0 ]->getValueTypes ()[$ i ]];
787- for ($ j = 1 ; $ j < count ($ singleConstantArrayList ); $ j ++) {
788- $ otherArray = $ singleConstantArrayList [$ j ];
789- if (! $ finalKeyTypes [$ i ]->equals ($ otherArray ->getKeyTypes ()[$ i ])) {
790- return null ;
791- }
792- 793- $ finalValueTypesMap [$ i ][] = $ otherArray ->getValueTypes ()[$ i ];
794- }
795- }
796- 797- $ finalValueTypes = array_map (
798- static fn (array $ types ) => self ::union (...$ types ),
799- $ finalValueTypesMap ,
800- );
801- 802- $ optionalKeys = array_unique (array_merge (
803- ...array_map (
804- static fn (ConstantArrayType $ t ) => $ t ->getOptionalKeys (),
805- $ singleConstantArrayList ,
806- ),
807- ));
808- 809- return new ConstantArrayType (
810- $ finalKeyTypes ,
811- $ finalValueTypes ,
812- $ singleConstantArrayList [0 ]->getNextAutoIndexes (),
813- $ optionalKeys ,
814- $ singleConstantArrayList [0 ]->isList (),
815- );
816- }
817- 818760 /**
819761 * @param Type[] $types
820762 * @return Type[]
@@ -900,16 +842,21 @@ private static function countConstantArrayValueTypes(array $types): int
900842 }
901843
902844 /**
903- * @param Type[] $constantArrays
904- * @return Type[]
845+ * @param list< Type> $constantArrays
846+ * @return list< Type>
905847 */
906- private static function reduceArrays (array $ constantArrays ): array
848+ private static function reduceArrays (array $ constantArrays, bool $ preserveTaggedUnions ): array
907849 {
908850 $ newArrays = [];
909851 $ arraysToProcess = [];
910852 $ emptyArray = null ;
911853 foreach ($ constantArrays as $ constantArray ) {
912854 if (!$ constantArray ->isConstantArray ()->yes ()) {
855+ // This is an optimization for current use-case of $preserveTaggedUnions=false, where we need
856+ // one constant array as a result, or we generalize the $constantArrays.
857+ if (!$ preserveTaggedUnions ) {
858+ return $ constantArrays ;
859+ }
913860 $ newArrays [] = $ constantArray ;
914861 continue ;
915862 }
@@ -955,7 +902,8 @@ private static function reduceArrays(array $constantArrays): array
955902 }
956903
957904 if (
958- $ overlappingKeysCount === count ($ arraysToProcess [$ i ]->getKeyTypes ())
905+ $ preserveTaggedUnions
906+ && $ overlappingKeysCount === count ($ arraysToProcess [$ i ]->getKeyTypes ())
959907 && $ arraysToProcess [$ j ]->isKeysSupersetOf ($ arraysToProcess [$ i ])
960908 ) {
961909 $ arraysToProcess [$ j ] = $ arraysToProcess [$ j ]->mergeWith ($ arraysToProcess [$ i ]);
@@ -964,13 +912,25 @@ private static function reduceArrays(array $constantArrays): array
964912 }
965913
966914 if (
967- $ overlappingKeysCount === count ($ arraysToProcess [$ j ]->getKeyTypes ())
915+ $ preserveTaggedUnions
916+ && $ overlappingKeysCount === count ($ arraysToProcess [$ j ]->getKeyTypes ())
968917 && $ arraysToProcess [$ i ]->isKeysSupersetOf ($ arraysToProcess [$ j ])
969918 ) {
970919 $ arraysToProcess [$ i ] = $ arraysToProcess [$ i ]->mergeWith ($ arraysToProcess [$ j ]);
971920 unset($ arraysToProcess [$ j ]);
972921 continue 1 ;
973922 }
923+ 924+ if (
925+ !$ preserveTaggedUnions
926+ // both arrays have same keys
927+ && $ overlappingKeysCount === count ($ arraysToProcess [$ i ]->getKeyTypes ())
928+ && $ overlappingKeysCount === count ($ arraysToProcess [$ j ]->getKeyTypes ())
929+ ) {
930+ $ arraysToProcess [$ j ] = $ arraysToProcess [$ j ]->mergeWith ($ arraysToProcess [$ i ]);
931+ unset($ arraysToProcess [$ i ]);
932+ continue 2 ;
933+ }
974934 }
975935 }
976936
0 commit comments