@@ -33,9 +33,11 @@ function (string $delimiter, $mixed) {
3333 * @param 'a,b'|'x;y;z' $stringUnion
3434 * @param 1|2 $limitUnion
3535 * @param int<1, 3> $limitRange
36+ * @param int<5, max> $largeLimitRange
37+ * @param int<-100, -2> $negativeLimitRange
3638 * @param ''|',' $maybeEmptyDelimiter
3739 */
38- function constantSplit (string $ delimiterUnion , string $ stringUnion , int $ limitUnion , int $ limitRange , string $ maybeEmptyDelimiter , string $ unknown , int $ unknownLimit ): void
40+ function constantSplit (string $ delimiterUnion , string $ stringUnion , int $ limitUnion , int $ limitRange , int $ largeLimitRange , int $ negativeLimitRange , string $ maybeEmptyDelimiter , string $ unknown , int $ unknownLimit ): void
3941{
4042 assertType ("array{'a', 'b', 'c'} " , explode (', ' , 'a,b,c ' ));
4143 assertType ("array{'App/Service::foo'} " , explode ('::: ' , 'App/Service::foo ' ));
@@ -51,33 +53,39 @@ function constantSplit(string $delimiterUnion, string $stringUnion, int $limitUn
5153 assertType ("array{'a', 'b,c'}|array{'a,b,c'} " , explode (', ' , 'a,b,c ' , $ limitUnion ));
5254 assertType ("array{'a', 'b', 'c'}|array{'a', 'b,c'}|array{'a,b,c'} " , explode (', ' , 'a,b,c ' , $ limitRange ));
5355
56+ // limits above the number of parts all produce the full split, limits at or
57+ // below minus the number of parts all produce an empty array
58+ assertType ("array{'a', 'b', 'c'} " , explode (', ' , 'a,b,c ' , $ largeLimitRange ));
59+ assertType ("array{}|array{'a'} " , explode (', ' , 'a,b,c ' , $ negativeLimitRange ));
60+ assertType ("array{}|array{'a,b,c'}|list{0: 'a', 1?: 'b'|'b,c', 2?: 'c'} " , explode (', ' , 'a,b,c ' , $ unknownLimit ));
61+
5462 // the empty separator throws a ValueError on PHP 8+, so only the ',' split remains
5563 assertType ("array{'a', 'b'} " , explode ($ maybeEmptyDelimiter , 'a,b ' ));
5664
5765 assertType ('non-empty-list<lowercase-string> ' , explode ($ unknown , 'a,b ' ));
5866 assertType ('non-empty-list<string> ' , explode (', ' , $ unknown ));
59- assertType ('list<lowercase-string> ' , explode (', ' , 'a,b,c ' , $ unknownLimit ));
6067}
6168
6269/**
6370 * @param ','|';' $twoDelimiters
6471 * @param 'a,b;c'|'x,y;z' $twoStrings
6572 * @param int<1, 4> $limitRangeAtLimit
66- * @param int<1, 5 > $limitRangeOverLimit
73+ * @param int<1, 20 > $limitRangeOverLimit
6774 * @param 'a'|'b'|'c'|'d'|'e' $fiveDelimiters
6875 * @param 'xay'|'xby'|'xcy'|'xdy' $fourStrings
6976 * @param int<1, 200> $wideLimitRange
7077 */
7178function constantSplitLimits (string $ twoDelimiters , string $ twoStrings , int $ limitRangeAtLimit , int $ limitRangeOverLimit , string $ fiveDelimiters , string $ fourStrings , int $ wideLimitRange ): void
7279{
73- // 2 delimiters * 2 strings * 4 limits is exactly CONSTANT_COMBINATION_LIMIT combinations
80+ // the clamping collapses int<1, 4> into the two limits that matter for a
81+ // two-part split, so this stays within CONSTANT_COMBINATION_LIMIT
7482 assertType ("array{'a', 'b;c'}|array{'a,b', 'c'}|array{'a,b;c'}|array{'x', 'y;z'}|array{'x,y', 'z'}|array{'x,y;z'} " , explode ($ twoDelimiters , $ twoStrings , $ limitRangeAtLimit ));
7583
76- // one more value in the limit range makes it 20 combinations , so the exact result is not computed
77- assertType ('non-empty-list<lowercase-string> ' , explode ($ twoDelimiters , $ twoStrings , $ limitRangeOverLimit ));
84+ // 20 limits that are not collapsed by the clamping are over the limit , so the exact result is not computed
85+ assertType ('non-empty-list<lowercase-string> ' , explode (' , ' , ' a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t ' , $ limitRangeOverLimit ));
7886
79- // the limit range is too wide to enumerate its finite types
80- assertType (' non-empty-list<lowercase-string> ' , explode (', ' , 'a,b ' , $ wideLimitRange ));
87+ // a range wider than the number of parts is clamped down to the limits that matter
88+ assertType (" array{'a', 'b'}|array{'a,b'} " , explode (', ' , 'a,b ' , $ wideLimitRange ));
8189
8290 // 5 delimiters * 4 strings is over the limit too
8391 assertType ('non-empty-list<lowercase-string> ' , explode ($ fiveDelimiters , $ fourStrings ));
0 commit comments