@@ -40,17 +40,44 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
40
40
} else {
41
41
$ type = $ this ->parseAtomic ($ tokens );
42
42
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
+ }
45
52
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 ;
48
60
}
49
61
}
50
62
51
63
return $ this ->enrichWithAttributes ($ tokens , $ type , $ startLine , $ startIndex );
52
64
}
53
65
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
+
54
81
/**
55
82
* @internal
56
83
* @template T of Ast\Node
@@ -90,7 +117,7 @@ private function subParse(TokenIterator $tokens): Ast\Type\TypeNode
90
117
if ($ tokens ->isCurrentTokenValue ('is ' )) {
91
118
$ type = $ this ->parseConditional ($ tokens , $ type );
92
119
} else {
93
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
120
+ $ tokens ->skipNewLineTokens ( );
94
121
95
122
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_UNION )) {
96
123
$ type = $ this ->subParseUnion ($ tokens , $ type );
@@ -112,9 +139,9 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
112
139
$ startIndex = $ tokens ->currentTokenIndex ();
113
140
114
141
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES )) {
115
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
142
+ $ tokens ->skipNewLineTokens ( );
116
143
$ type = $ this ->subParse ($ tokens );
117
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
144
+ $ tokens ->skipNewLineTokens ( );
118
145
119
146
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_PARENTHESES );
120
147
@@ -256,9 +283,9 @@ private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type):
256
283
$ types = [$ type ];
257
284
258
285
while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_UNION )) {
259
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
286
+ $ tokens ->skipNewLineTokens ( );
260
287
$ types [] = $ this ->parseAtomic ($ tokens );
261
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
288
+ $ tokens ->skipNewLineTokens ( );
262
289
}
263
290
264
291
return new Ast \Type \UnionTypeNode ($ types );
@@ -284,9 +311,9 @@ private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $
284
311
$ types = [$ type ];
285
312
286
313
while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_INTERSECTION )) {
287
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
314
+ $ tokens ->skipNewLineTokens ( );
288
315
$ types [] = $ this ->parseAtomic ($ tokens );
289
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
316
+ $ tokens ->skipNewLineTokens ( );
290
317
}
291
318
292
319
return new Ast \Type \IntersectionTypeNode ($ types );
@@ -306,15 +333,15 @@ private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subj
306
333
307
334
$ targetType = $ this ->parse ($ tokens );
308
335
309
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
336
+ $ tokens ->skipNewLineTokens ( );
310
337
$ tokens ->consumeTokenType (Lexer::TOKEN_NULLABLE );
311
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
338
+ $ tokens ->skipNewLineTokens ( );
312
339
313
340
$ ifType = $ this ->parse ($ tokens );
314
341
315
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
342
+ $ tokens ->skipNewLineTokens ( );
316
343
$ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
317
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
344
+ $ tokens ->skipNewLineTokens ( );
318
345
319
346
$ elseType = $ this ->subParse ($ tokens );
320
347
@@ -335,15 +362,15 @@ private function parseConditionalForParameter(TokenIterator $tokens, string $par
335
362
336
363
$ targetType = $ this ->parse ($ tokens );
337
364
338
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
365
+ $ tokens ->skipNewLineTokens ( );
339
366
$ tokens ->consumeTokenType (Lexer::TOKEN_NULLABLE );
340
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
367
+ $ tokens ->skipNewLineTokens ( );
341
368
342
369
$ ifType = $ this ->parse ($ tokens );
343
370
344
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
371
+ $ tokens ->skipNewLineTokens ( );
345
372
$ tokens ->consumeTokenType (Lexer::TOKEN_COLON );
346
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
373
+ $ tokens ->skipNewLineTokens ( );
347
374
348
375
$ elseType = $ this ->subParse ($ tokens );
349
376
@@ -409,8 +436,11 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
409
436
$ variances = [];
410
437
411
438
$ 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 ();
414
444
415
445
// trailing comma case
416
446
if (!$ isFirst && $ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET )) {
@@ -419,7 +449,7 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
419
449
$ isFirst = false ;
420
450
421
451
[$ genericTypes [], $ variances []] = $ this ->parseGenericTypeArgument ($ tokens );
422
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
452
+ $ tokens ->skipNewLineTokens ( );
423
453
}
424
454
425
455
$ type = new Ast \Type \GenericTypeNode ($ baseType , $ genericTypes , $ variances );
@@ -510,19 +540,19 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
510
540
: [];
511
541
512
542
$ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES );
513
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
543
+ $ tokens ->skipNewLineTokens ( );
514
544
515
545
$ parameters = [];
516
546
if (!$ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_PARENTHESES )) {
517
547
$ parameters [] = $ this ->parseCallableParameter ($ tokens );
518
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
548
+ $ tokens ->skipNewLineTokens ( );
519
549
while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
520
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
550
+ $ tokens ->skipNewLineTokens ( );
521
551
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_PARENTHESES )) {
522
552
break ;
523
553
}
524
554
$ parameters [] = $ this ->parseCallableParameter ($ tokens );
525
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
555
+ $ tokens ->skipNewLineTokens ( );
526
556
}
527
557
}
528
558
@@ -550,7 +580,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
550
580
551
581
$ isFirst = true ;
552
582
while ($ isFirst || $ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
553
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
583
+ $ tokens ->skipNewLineTokens ( );
554
584
555
585
// trailing comma case
556
586
if (!$ isFirst && $ tokens ->isCurrentTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET )) {
@@ -559,7 +589,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
559
589
$ isFirst = false ;
560
590
561
591
$ templates [] = $ this ->parseCallableTemplateArgument ($ tokens );
562
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
592
+ $ tokens ->skipNewLineTokens ( );
563
593
}
564
594
565
595
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET );
@@ -830,7 +860,7 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
830
860
$ unsealedType = null ;
831
861
832
862
do {
833
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
863
+ $ tokens ->skipNewLineTokens ( );
834
864
835
865
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
836
866
return Ast \Type \ArrayShapeNode::createSealed ($ items , $ kind );
@@ -839,14 +869,14 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
839
869
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_VARIADIC )) {
840
870
$ sealed = false ;
841
871
842
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
872
+ $ tokens ->skipNewLineTokens ( );
843
873
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_OPEN_ANGLE_BRACKET )) {
844
874
if ($ kind === Ast \Type \ArrayShapeNode::KIND_ARRAY ) {
845
875
$ unsealedType = $ this ->parseArrayShapeUnsealedType ($ tokens );
846
876
} else {
847
877
$ unsealedType = $ this ->parseListShapeUnsealedType ($ tokens );
848
878
}
849
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
879
+ $ tokens ->skipNewLineTokens ( );
850
880
}
851
881
852
882
$ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA );
@@ -855,10 +885,10 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
855
885
856
886
$ items [] = $ this ->parseArrayShapeItem ($ tokens );
857
887
858
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
888
+ $ tokens ->skipNewLineTokens ( );
859
889
} while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA ));
860
890
861
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
891
+ $ tokens ->skipNewLineTokens ( );
862
892
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET );
863
893
864
894
if ($ sealed ) {
@@ -945,18 +975,18 @@ private function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\Type\Ar
945
975
$ startIndex = $ tokens ->currentTokenIndex ();
946
976
947
977
$ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_ANGLE_BRACKET );
948
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
978
+ $ tokens ->skipNewLineTokens ( );
949
979
950
980
$ valueType = $ this ->parse ($ tokens );
951
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
981
+ $ tokens ->skipNewLineTokens ( );
952
982
953
983
$ keyType = null ;
954
984
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA )) {
955
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
985
+ $ tokens ->skipNewLineTokens ( );
956
986
957
987
$ keyType = $ valueType ;
958
988
$ valueType = $ this ->parse ($ tokens );
959
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
989
+ $ tokens ->skipNewLineTokens ( );
960
990
}
961
991
962
992
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET );
@@ -978,10 +1008,10 @@ private function parseListShapeUnsealedType(TokenIterator $tokens): Ast\Type\Arr
978
1008
$ startIndex = $ tokens ->currentTokenIndex ();
979
1009
980
1010
$ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_ANGLE_BRACKET );
981
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1011
+ $ tokens ->skipNewLineTokens ( );
982
1012
983
1013
$ valueType = $ this ->parse ($ tokens );
984
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1014
+ $ tokens ->skipNewLineTokens ( );
985
1015
986
1016
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_ANGLE_BRACKET );
987
1017
@@ -1003,18 +1033,18 @@ private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNo
1003
1033
$ items = [];
1004
1034
1005
1035
do {
1006
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1036
+ $ tokens ->skipNewLineTokens ( );
1007
1037
1008
1038
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET )) {
1009
1039
return new Ast \Type \ObjectShapeNode ($ items );
1010
1040
}
1011
1041
1012
1042
$ items [] = $ this ->parseObjectShapeItem ($ tokens );
1013
1043
1014
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1044
+ $ tokens ->skipNewLineTokens ( );
1015
1045
} while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA ));
1016
1046
1017
- $ tokens ->tryConsumeTokenType (Lexer:: TOKEN_PHPDOC_EOL );
1047
+ $ tokens ->skipNewLineTokens ( );
1018
1048
$ tokens ->consumeTokenType (Lexer::TOKEN_CLOSE_CURLY_BRACKET );
1019
1049
1020
1050
return new Ast \Type \ObjectShapeNode ($ items );
0 commit comments