@@ -44,8 +44,6 @@ public static function remove(Type $fromType, Type $typeToRemove): Type
4444 $ isSuperType = $ typeToRemove ->isSuperTypeOf ($ fromType );
4545 if ($ isSuperType ->yes ()) {
4646 return new NeverType ();
47- } elseif ($ isSuperType ->no ()) {
48- return $ fromType ;
4947 }
5048
5149 if ($ fromType instanceof BooleanType) {
@@ -62,29 +60,47 @@ public static function remove(Type $fromType, Type $typeToRemove): Type
6260 return $ arrayType ;
6361 }
6462 } elseif ($ fromType instanceof IntegerRangeType || $ fromType instanceof IntegerType) {
65- $ minA = $ fromType instanceof IntegerRangeType ? $ fromType ->getMin () : PHP_INT_MIN ;
66- $ maxA = $ fromType instanceof IntegerRangeType ? $ fromType ->getMax () : PHP_INT_MAX ;
63+ if ($ fromType instanceof ConstantIntegerType) {
64+ $ minA = $ fromType ->getValue ();
65+ $ maxA = $ fromType ->getValue ();
66+ } else {
67+ $ minA = $ fromType instanceof IntegerRangeType ? $ fromType ->getMin () : PHP_INT_MIN ;
68+ $ maxA = $ fromType instanceof IntegerRangeType ? $ fromType ->getMax () : PHP_INT_MAX ;
69+ }
6770
6871 if ($ typeToRemove instanceof IntegerRangeType) {
69- if ($ typeToRemove ->getMax () >= $ maxA ) {
70- return IntegerRangeType::fromInterval (
71- $ minA ,
72- $ typeToRemove ->getMin () - 1
72+ $ removeValueMin = $ typeToRemove ->getMin ();
73+ $ removeValueMax = $ typeToRemove ->getMax ();
74+ if ($ minA < $ removeValueMin && $ removeValueMax < $ maxA ) {
75+ return self ::union (
76+ IntegerRangeType::fromInterval ($ minA , $ removeValueMin - 1 ),
77+ IntegerRangeType::fromInterval ($ removeValueMax + 1 , $ maxA )
7378 );
7479 }
75-
76- if ($ typeToRemove ->getMin () <= $ minA ) {
80+ if ($ removeValueMin <= $ minA && $ minA <= $ removeValueMax ) {
7781 return IntegerRangeType::fromInterval (
78- $ typeToRemove -> getMax () + 1 ,
82+ $ removeValueMax === PHP_INT_MAX ? PHP_INT_MAX : $ removeValueMax + 1 ,
7983 $ maxA
8084 );
8185 }
86+ if ($ removeValueMin <= $ maxA && $ maxA <= $ removeValueMax ) {
87+ return IntegerRangeType::fromInterval (
88+ $ minA ,
89+ $ removeValueMin === PHP_INT_MIN ? PHP_INT_MIN : $ removeValueMin - 1
90+ );
91+ }
8292 } elseif ($ typeToRemove instanceof ConstantIntegerType) {
83- if ($ typeToRemove ->getValue () === $ minA ) {
93+ $ removeValue = $ typeToRemove ->getValue ();
94+ if ($ minA < $ removeValue && $ removeValue < $ maxA ) {
95+ return self ::union (
96+ IntegerRangeType::fromInterval ($ minA , $ removeValue - 1 ),
97+ IntegerRangeType::fromInterval ($ removeValue + 1 , $ maxA )
98+ );
99+ }
100+ if ($ removeValue === $ minA ) {
84101 return IntegerRangeType::fromInterval ($ minA + 1 , $ maxA );
85102 }
86-
87- if ($ typeToRemove ->getValue () === $ maxA ) {
103+ if ($ removeValue === $ maxA ) {
88104 return IntegerRangeType::fromInterval ($ minA , $ maxA - 1 );
89105 }
90106 }
@@ -269,22 +285,36 @@ public static function union(Type ...$types): Type
269285 for ($ i = 0 ; $ i < count ($ types ); $ i ++) {
270286 for ($ j = $ i + 1 ; $ j < count ($ types ); $ j ++) {
271287 if ($ types [$ i ] instanceof IntegerRangeType) {
272- if ($ types [$ j ] instanceof IntegerRangeType && $ types [$ i ]->isSuperTypeOf ($ types [$ j ])->maybe ()) {
273- $ types [$ i ] = IntegerRangeType::fromInterval (
274- min ($ types [$ i ]->getMin (), $ types [$ j ]->getMin ()),
275- max ($ types [$ i ]->getMax (), $ types [$ j ]->getMax ())
276- );
277- array_splice ($ types , $ j , 1 );
278- continue 2 ;
288+ if ($ types [$ j ] instanceof IntegerRangeType) {
289+ if (
290+ $ types [$ i ]->isSuperTypeOf ($ types [$ j ])->maybe () ||
291+ $ types [$ i ]->getMax () + 1 === $ types [$ j ]->getMin () ||
292+ $ types [$ j ]->getMax () + 1 === $ types [$ i ]->getMin ()
293+ ) {
294+ $ types [$ i ] = IntegerRangeType::fromInterval (
295+ min ($ types [$ i ]->getMin (), $ types [$ j ]->getMin ()),
296+ max ($ types [$ i ]->getMax (), $ types [$ j ]->getMax ())
297+ );
298+ $ i --;
299+ array_splice ($ types , $ j , 1 );
300+ continue 2 ;
301+ }
279302 }
280303
281304 if ($ types [$ j ] instanceof ConstantIntegerType) {
282- $ types [$ i ] = IntegerRangeType::fromInterval (
283- min ($ types [$ i ]->getMin (), $ types [$ j ]->getValue ()),
284- max ($ types [$ i ]->getMax (), $ types [$ j ]->getValue ())
285- );
286- array_splice ($ types , $ j , 1 );
287- continue 2 ;
305+ $ value = $ types [$ j ]->getValue ();
306+ if ($ types [$ i ]->getMin () === $ value + 1 ) {
307+ $ types [$ i ] = IntegerRangeType::fromInterval ($ value , $ types [$ i ]->getMax ());
308+ $ i --;
309+ array_splice ($ types , $ j , 1 );
310+ continue 2 ;
311+ }
312+ if ($ types [$ i ]->getMax () === $ value - 1 ) {
313+ $ types [$ i ] = IntegerRangeType::fromInterval ($ types [$ i ]->getMin (), $ value );
314+ $ i --;
315+ array_splice ($ types , $ j , 1 );
316+ continue 2 ;
317+ }
288318 }
289319 }
290320
@@ -629,10 +659,7 @@ public static function intersect(Type ...$types): Type
629659 $ isSuperTypeA = $ types [$ j ]->isSuperTypeOf ($ types [$ i ]);
630660 }
631661
632- if ($ isSuperTypeA ->no ()) {
633- return new NeverType ();
634-
635- } elseif ($ isSuperTypeA ->yes ()) {
662+ if ($ isSuperTypeA ->yes ()) {
636663 array_splice ($ types , $ j --, 1 );
637664 continue ;
638665 }
@@ -659,6 +686,10 @@ public static function intersect(Type ...$types): Type
659686 array_splice ($ types , $ i --, 1 );
660687 continue 2 ;
661688 }
689+
690+ if ($ isSuperTypeA ->no ()) {
691+ return new NeverType ();
692+ }
662693 }
663694 }
664695
0 commit comments