@@ -40,17 +40,44 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
4040 } else {
4141 $ type = $ this ->parseAtomic ($ tokens );
4242
43- if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_UNION )) {
44- $ type = $ this ->parseUnion ($ tokens , $ type );
43+ $ tokens ->pushSavePoint ();
44+ $ tokens ->skipNewLineTokens ();
45+
46+ try {
47+ $ enrichedType = $ this ->enrichTypeOnUnionOrIntersection ($ tokens , $ type );
48+
49+ } catch (ParserException $ parserException ) {
50+ $ enrichedType = null ;
51+ }
4552
46- } elseif ($ tokens ->isCurrentTokenType (Lexer::TOKEN_INTERSECTION )) {
47- $ type = $ this ->parseIntersection ($ tokens , $ type );
53+ if ($ enrichedType !== null ) {
54+ $ type = $ enrichedType ;
55+ $ tokens ->dropSavePoint ();
56+
57+ } else {
58+ $ tokens ->rollback ();
59+ $ type = $ this ->enrichTypeOnUnionOrIntersection ($ tokens , $ type ) ?? $ type ;
4860 }
4961 }
5062
5163 return $ this ->enrichWithAttributes ($ tokens , $ type , $ startLine , $ startIndex );
5264 }
5365
66+ /** @phpstan-impure */
67+ private function enrichTypeOnUnionOrIntersection (TokenIterator $ tokens , Ast \Type \TypeNode $ type ): ?Ast \Type \TypeNode
68+ {
69+ if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_UNION )) {
70+ return $ this ->parseUnion ($ tokens , $ type );
71+
72+ }
73+
74+ if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_INTERSECTION )) {
75+ return $ this ->parseIntersection ($ tokens , $ type );
76+ }
77+
78+ return null ;
79+ }
80+
5481 /**
5582 * @internal
5683 * @template T of Ast\Node
@@ -90,7 +117,7 @@ private function subParse(TokenIterator $tokens): Ast\Type\TypeNode
90117 if ($ tokens ->isCurrentTokenValue ('is ' )) {
91118 $ type = $ this ->parseConditional ($ tokens , $ type );
92119 } else {
93- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
120+ $ tokens ->skipNewLineTokens ( );
94121
95122 if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_UNION )) {
96123 $ type = $ this ->subParseUnion ($ tokens , $ type );
@@ -112,9 +139,9 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
112139 $ startIndex = $ tokens ->currentTokenIndex ();
113140
114141 if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES )) {
115- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
142+ $ tokens ->skipNewLineTokens ( );
116143 $ type = $ this ->subParse ($ tokens );
117- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
144+ $ tokens ->skipNewLineTokens ( );
118145
119146 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_PARENTHESES );
120147
@@ -256,9 +283,9 @@ private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type):
256283 $ types = [$ type ];
257284
258285 while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_UNION )) {
259- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
286+ $ tokens ->skipNewLineTokens ( );
260287 $ types [] = $ this ->parseAtomic ($ tokens );
261- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
288+ $ tokens ->skipNewLineTokens ( );
262289 }
263290
264291 return new Ast \Type \UnionTypeNode ($ types );
@@ -284,9 +311,9 @@ private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $
284311 $ types = [$ type ];
285312
286313 while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_INTERSECTION )) {
287- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
314+ $ tokens ->skipNewLineTokens ( );
288315 $ types [] = $ this ->parseAtomic ($ tokens );
289- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
316+ $ tokens ->skipNewLineTokens ( );
290317 }
291318
292319 return new Ast \Type \IntersectionTypeNode ($ types );
@@ -306,15 +333,15 @@ private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subj
306333
307334 $ targetType = $ this ->parse ($ tokens );
308335
309- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
336+ $ tokens ->skipNewLineTokens ( );
310337 $ tokens ->consumeTokenType (Lexer::TOKEN_NULLABLE );
311- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
338+ $ tokens ->skipNewLineTokens ( );
312339
313340 $ ifType = $ this ->parse ($ tokens );
314341
315- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
342+ $ tokens ->skipNewLineTokens ( );
316343 $ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
317- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
344+ $ tokens ->skipNewLineTokens ( );
318345
319346 $ elseType = $ this ->subParse ($ tokens );
320347
@@ -335,15 +362,15 @@ private function parseConditionalForParameter(TokenIterator $tokens, string $par
335362
336363 $ targetType = $ this ->parse ($ tokens );
337364
338- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
365+ $ tokens ->skipNewLineTokens ( );
339366 $ tokens ->consumeTokenType (Lexer::TOKEN_NULLABLE );
340- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
367+ $ tokens ->skipNewLineTokens ( );
341368
342369 $ ifType = $ this ->parse ($ tokens );
343370
344- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
371+ $ tokens ->skipNewLineTokens ( );
345372 $ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
346- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
373+ $ tokens ->skipNewLineTokens ( );
347374
348375 $ elseType = $ this ->subParse ($ tokens );
349376
@@ -409,8 +436,11 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
409436 $ variances = [];
410437
411438 $ isFirst = true ;
412- while ($ isFirst || $ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
413- $ tokens ->tryConsumeTokenType (Lexer::TOKEN_PHPDOC_EOL );
439+ while (
440+ $ isFirst
441+ || $ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )
442+ ) {
443+ $ tokens ->skipNewLineTokens ();
414444
415445 // trailing comma case
416446 if (!$ isFirst && $ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET )) {
@@ -419,7 +449,7 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
419449 $ isFirst = false ;
420450
421451 [$ genericTypes [], $ variances []] = $ this ->parseGenericTypeArgument ($ tokens );
422- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
452+ $ tokens ->skipNewLineTokens ( );
423453 }
424454
425455 $ type = new Ast \Type \GenericTypeNode ($ baseType , $ genericTypes , $ variances );
@@ -510,19 +540,19 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
510540 : [];
511541
512542 $ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES );
513- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
543+ $ tokens ->skipNewLineTokens ( );
514544
515545 $ parameters = [];
516546 if (!$ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_PARENTHESES )) {
517547 $ parameters [] = $ this ->parseCallableParameter ($ tokens );
518- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
548+ $ tokens ->skipNewLineTokens ( );
519549 while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
520- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
550+ $ tokens ->skipNewLineTokens ( );
521551 if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_PARENTHESES )) {
522552 break ;
523553 }
524554 $ parameters [] = $ this ->parseCallableParameter ($ tokens );
525- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
555+ $ tokens ->skipNewLineTokens ( );
526556 }
527557 }
528558
@@ -550,7 +580,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
550580
551581 $ isFirst = true ;
552582 while ($ isFirst || $ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
553- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
583+ $ tokens ->skipNewLineTokens ( );
554584
555585 // trailing comma case
556586 if (!$ isFirst && $ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET )) {
@@ -559,7 +589,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
559589 $ isFirst = false ;
560590
561591 $ templates [] = $ this ->parseCallableTemplateArgument ($ tokens );
562- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
592+ $ tokens ->skipNewLineTokens ( );
563593 }
564594
565595 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET );
@@ -830,7 +860,7 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
830860 $ unsealedType = null ;
831861
832862 do {
833- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
863+ $ tokens ->skipNewLineTokens ( );
834864
835865 if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
836866 return Ast \Type \ArrayShapeNode::createSealed ($ items , $ kind );
@@ -839,14 +869,14 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
839869 if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_VARIADIC )) {
840870 $ sealed = false ;
841871
842- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
872+ $ tokens ->skipNewLineTokens ( );
843873 if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_ANGLE_BRACKET )) {
844874 if ($ kind === Ast \Type \ArrayShapeNode::KIND_ARRAY ) {
845875 $ unsealedType = $ this ->parseArrayShapeUnsealedType ($ tokens );
846876 } else {
847877 $ unsealedType = $ this ->parseListShapeUnsealedType ($ tokens );
848878 }
849- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
879+ $ tokens ->skipNewLineTokens ( );
850880 }
851881
852882 $ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA );
@@ -855,10 +885,10 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
855885
856886 $ items [] = $ this ->parseArrayShapeItem ($ tokens );
857887
858- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
888+ $ tokens ->skipNewLineTokens ( );
859889 } while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA ));
860890
861- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
891+ $ tokens ->skipNewLineTokens ( );
862892 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET );
863893
864894 if ($ sealed ) {
@@ -945,18 +975,18 @@ private function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\Type\Ar
945975 $ startIndex = $ tokens ->currentTokenIndex ();
946976
947977 $ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_ANGLE_BRACKET );
948- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
978+ $ tokens ->skipNewLineTokens ( );
949979
950980 $ valueType = $ this ->parse ($ tokens );
951- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
981+ $ tokens ->skipNewLineTokens ( );
952982
953983 $ keyType = null ;
954984 if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
955- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
985+ $ tokens ->skipNewLineTokens ( );
956986
957987 $ keyType = $ valueType ;
958988 $ valueType = $ this ->parse ($ tokens );
959- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
989+ $ tokens ->skipNewLineTokens ( );
960990 }
961991
962992 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET );
@@ -978,10 +1008,10 @@ private function parseListShapeUnsealedType(TokenIterator $tokens): Ast\Type\Arr
9781008 $ startIndex = $ tokens ->currentTokenIndex ();
9791009
9801010 $ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_ANGLE_BRACKET );
981- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1011+ $ tokens ->skipNewLineTokens ( );
9821012
9831013 $ valueType = $ this ->parse ($ tokens );
984- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1014+ $ tokens ->skipNewLineTokens ( );
9851015
9861016 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET );
9871017
@@ -1003,18 +1033,18 @@ private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNo
10031033 $ items = [];
10041034
10051035 do {
1006- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1036+ $ tokens ->skipNewLineTokens ( );
10071037
10081038 if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
10091039 return new Ast \Type \ObjectShapeNode ($ items );
10101040 }
10111041
10121042 $ items [] = $ this ->parseObjectShapeItem ($ tokens );
10131043
1014- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1044+ $ tokens ->skipNewLineTokens ( );
10151045 } while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA ));
10161046
1017- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1047+ $ tokens ->skipNewLineTokens ( );
10181048 $ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET );
10191049
10201050 return new Ast \Type \ObjectShapeNode ($ items );
0 commit comments