@@ -107,12 +107,17 @@ private function matchPatternType(Type $patternType, ?Type $flagsType, TrinaryLo
107107 */
108108 private function matchRegex (string $ regex , ?int $ flags , TrinaryLogic $ wasMatched , bool $ matchesAll ): ?Type
109109 {
110- $ parseResult = $ this ->regexGroupParser ->parseGroups ($ regex );
111- if ($ parseResult === null ) {
110+ $ astWalkResult = $ this ->regexGroupParser ->parseGroups ($ regex );
111+ if ($ astWalkResult === null ) {
112112 // regex could not be parsed by Hoa/Regex
113113 return null ;
114114 }
115- [$ groupList , $ markVerbs ] = $ parseResult ;
115+ $ groupList = $ astWalkResult ->getCapturingGroups ();
116+ $ markVerbs = $ astWalkResult ->getMarkVerbs ();
117+ $ subjectBaseType = new StringType ();
118+ if ($ wasMatched ->yes ()) {
119+ $ subjectBaseType = $ astWalkResult ->getSubjectBaseType ();
120+ }
116121
117122 $ regexGroupList = new RegexGroupList ($ groupList );
118123 $ trailingOptionals = $ regexGroupList ->countTrailingOptionals ();
@@ -130,6 +135,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
130135 $ regexGroupList = $ regexGroupList ->forceGroupNonOptional ($ onlyOptionalTopLevelGroup );
131136
132137 $ combiType = $ this ->buildArrayType (
138+ $ subjectBaseType ,
133139 $ regexGroupList ,
134140 $ wasMatched ,
135141 $ trailingOptionals ,
@@ -141,7 +147,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
141147 if (!$ this ->containsUnmatchedAsNull ($ flags , $ matchesAll )) {
142148 // positive match has a subject but not any capturing group
143149 $ combiType = TypeCombinator::union (
144- new ConstantArrayType ([new ConstantIntegerType (0 )], [$ this ->createSubjectValueType ($ flags , $ matchesAll )], [1 ], [], TrinaryLogic::createYes ()),
150+ new ConstantArrayType ([new ConstantIntegerType (0 )], [$ this ->createSubjectValueType ($ subjectBaseType , $ flags , $ matchesAll )], [1 ], [], TrinaryLogic::createYes ()),
145151 $ combiType ,
146152 );
147153 }
@@ -180,6 +186,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
180186 }
181187
182188 $ combiType = $ this ->buildArrayType (
189+ $ subjectBaseType ,
183190 $ comboList ,
184191 $ wasMatched ,
185192 $ trailingOptionals ,
@@ -199,7 +206,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
199206 )
200207 ) {
201208 // positive match has a subject but not any capturing group
202- $ combiTypes [] = new ConstantArrayType ([new ConstantIntegerType (0 )], [$ this ->createSubjectValueType ($ flags , $ matchesAll )], [1 ], [], TrinaryLogic::createYes ());
209+ $ combiTypes [] = new ConstantArrayType ([new ConstantIntegerType (0 )], [$ this ->createSubjectValueType ($ subjectBaseType , $ flags , $ matchesAll )], [1 ], [], TrinaryLogic::createYes ());
203210 }
204211
205212 return TypeCombinator::union (...$ combiTypes );
@@ -208,6 +215,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
208215 // the general case, which should work in all cases but does not yield the most
209216 // precise result possible in some cases
210217 return $ this ->buildArrayType (
218+ $ subjectBaseType ,
211219 $ regexGroupList ,
212220 $ wasMatched ,
213221 $ trailingOptionals ,
@@ -221,6 +229,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
221229 * @param list<string> $markVerbs
222230 */
223231 private function buildArrayType (
232+ Type $ subjectBaseType ,
224233 RegexGroupList $ captureGroups ,
225234 TrinaryLogic $ wasMatched ,
226235 int $ trailingOptionals ,
@@ -234,7 +243,7 @@ private function buildArrayType(
234243 // first item in matches contains the overall match.
235244 $ builder ->setOffsetValueType (
236245 $ this ->getKeyType (0 ),
237- $ this ->createSubjectValueType ($ flags , $ matchesAll ),
246+ $ this ->createSubjectValueType ($ subjectBaseType , $ flags , $ matchesAll ),
238247 $ this ->isSubjectOptional ($ wasMatched , $ matchesAll ),
239248 );
240249
@@ -298,13 +307,21 @@ private function isSubjectOptional(TrinaryLogic $wasMatched, bool $matchesAll):
298307 return !$ wasMatched ->yes ();
299308 }
300309
301- private function createSubjectValueType (int $ flags , bool $ matchesAll ): Type
310+ /**
311+ * @param Type $baseType A string type (or string variant) representing the subject of the match
312+ */
313+ private function createSubjectValueType (Type $ baseType , int $ flags , bool $ matchesAll ): Type
302314 {
303- $ subjectValueType = TypeCombinator::removeNull ($ this ->getValueType (new StringType () , $ flags , $ matchesAll ));
315+ $ subjectValueType = TypeCombinator::removeNull ($ this ->getValueType ($ baseType , $ flags , $ matchesAll ));
304316
305317 if ($ matchesAll ) {
318+ $ subjectValueType = TypeCombinator::removeNull ($ this ->getValueType (new StringType (), $ flags , $ matchesAll ));
319+
306320 if ($ this ->containsPatternOrder ($ flags )) {
307- $ subjectValueType = TypeCombinator::intersect (new ArrayType (new IntegerType (), $ subjectValueType ), new AccessoryArrayListType ());
321+ $ subjectValueType = TypeCombinator::intersect (
322+ new ArrayType (new IntegerType (), $ subjectValueType ),
323+ new AccessoryArrayListType (),
324+ );
308325 }
309326 }
310327
0 commit comments