@@ -577,6 +577,11 @@ extension Parser {
577
577
}
578
578
579
579
extension Parser {
580
+ /// Whether the parser is at the start of an InlineArray type sugar body.
581
+ func isAtStartOfInlineArrayTypeBody( ) -> Bool {
582
+ withLookahead { $0. canParseStartOfInlineArrayTypeBody ( ) }
583
+ }
584
+
580
585
/// Parse an array or dictionary type..
581
586
mutating func parseCollectionType( ) -> RawTypeSyntax {
582
587
if let remaingingTokens = remainingTokensIfMaximumNestingLevelReached ( ) {
@@ -592,6 +597,15 @@ extension Parser {
592
597
}
593
598
594
599
let ( unexpectedBeforeLSquare, leftsquare) = self . expect ( . leftSquare)
600
+
601
+ // Check to see if we're at the start of an InlineArray type.
602
+ if self . isAtStartOfInlineArrayTypeBody ( ) {
603
+ return self . parseInlineArrayType (
604
+ unexpectedBeforeLSquare: unexpectedBeforeLSquare,
605
+ leftSquare: leftsquare
606
+ )
607
+ }
608
+
595
609
let firstType = self . parseType ( )
596
610
if let colon = self . consume ( if: . colon) {
597
611
let secondType = self . parseType ( )
@@ -622,6 +636,39 @@ extension Parser {
622
636
)
623
637
}
624
638
}
639
+
640
+ mutating func parseInlineArrayType(
641
+ unexpectedBeforeLSquare: RawUnexpectedNodesSyntax ? ,
642
+ leftSquare: RawTokenSyntax
643
+ ) -> RawTypeSyntax {
644
+ precondition ( self . experimentalFeatures. contains ( . inlineArrayTypeSugar) )
645
+
646
+ // We allow both values and types here and for the element type for
647
+ // better recovery in cases where the user writes e.g '[Int x 3]'.
648
+ let count = self . parseGenericArgumentType ( )
649
+
650
+ let ( unexpectedBeforeSeparator, separator) = self . expect (
651
+ TokenSpec ( . x, allowAtStartOfLine: false )
652
+ )
653
+
654
+ let element = self . parseGenericArgumentType ( )
655
+
656
+ let ( unexpectedBeforeRightSquare, rightSquare) = self . expect ( . rightSquare)
657
+
658
+ return RawTypeSyntax (
659
+ RawInlineArrayTypeSyntax (
660
+ unexpectedBeforeLSquare,
661
+ leftSquare: leftSquare,
662
+ count: . init( argument: count, trailingComma: nil , arena: self . arena) ,
663
+ unexpectedBeforeSeparator,
664
+ separator: separator,
665
+ element: . init( argument: element, trailingComma: nil , arena: self . arena) ,
666
+ unexpectedBeforeRightSquare,
667
+ rightSquare: rightSquare,
668
+ arena: self . arena
669
+ )
670
+ )
671
+ }
625
672
}
626
673
627
674
extension Parser . Lookahead {
@@ -714,15 +761,7 @@ extension Parser.Lookahead {
714
761
}
715
762
case TokenSpec ( . leftSquare) :
716
763
self . consumeAnyToken ( )
717
- guard self . canParseType ( ) else {
718
- return false
719
- }
720
- if self . consume ( if: . colon) != nil {
721
- guard self . canParseType ( ) else {
722
- return false
723
- }
724
- }
725
- guard self . consume ( if: . rightSquare) != nil else {
764
+ guard self . canParseCollectionTypeBody ( ) else {
726
765
return false
727
766
}
728
767
case TokenSpec ( . wildcard) :
@@ -762,6 +801,59 @@ extension Parser.Lookahead {
762
801
return true
763
802
}
764
803
804
+ /// Checks whether we can parse the start of an InlineArray type. This does
805
+ /// not include the element type.
806
+ mutating func canParseStartOfInlineArrayTypeBody( ) -> Bool {
807
+ guard self . experimentalFeatures. contains ( . inlineArrayTypeSugar) else {
808
+ return false
809
+ }
810
+
811
+ // We must have at least '[<type-or-integer> x', which cannot be any other
812
+ // kind of expression or type. We specifically look for both types and
813
+ // integers for better recovery in e.g cases where the user writes e.g
814
+ // '[Int x 2]'. We only do type-scalar since variadics would be ambiguous
815
+ // e.g 'Int...x'.
816
+ guard self . canParseTypeScalar ( ) || self . canParseIntegerLiteral ( ) else {
817
+ return false
818
+ }
819
+
820
+ // We don't currently allow multi-line since that would require
821
+ // disambiguation with array literals.
822
+ return self . consume ( if: TokenSpec ( . x, allowAtStartOfLine: false ) ) != nil
823
+ }
824
+
825
+ mutating func canParseInlineArrayTypeBody( ) -> Bool {
826
+ guard self . canParseStartOfInlineArrayTypeBody ( ) else {
827
+ return false
828
+ }
829
+ // Note we look for both types and integers for better recovery in e.g cases
830
+ // where the user writes e.g '[Int x 2]'.
831
+ guard self . canParseGenericArgument ( ) else {
832
+ return false
833
+ }
834
+ return self . consume ( if: . rightSquare) != nil
835
+ }
836
+
837
+ mutating func canParseCollectionTypeBody( ) -> Bool {
838
+ // Check to see if we have an InlineArray sugar type.
839
+ if self . experimentalFeatures. contains ( . inlineArrayTypeSugar) {
840
+ var lookahead = self . lookahead ( )
841
+ if lookahead. canParseInlineArrayTypeBody ( ) {
842
+ self = lookahead
843
+ return true
844
+ }
845
+ }
846
+ guard self . canParseType ( ) else {
847
+ return false
848
+ }
849
+ if self . consume ( if: . colon) != nil {
850
+ guard self . canParseType ( ) else {
851
+ return false
852
+ }
853
+ }
854
+ return self . consume ( if: . rightSquare) != nil
855
+ }
856
+
765
857
mutating func canParseTupleBodyType( ) -> Bool {
766
858
guard
767
859
!self . at ( . rightParen, . rightBrace) && !self . atContextualPunctuator ( " ... " )
@@ -863,6 +955,24 @@ extension Parser.Lookahead {
863
955
return lookahead. currentToken. isGenericTypeDisambiguatingToken
864
956
}
865
957
958
+ mutating func canParseIntegerLiteral( ) -> Bool {
959
+ if self . currentToken. tokenText == " - " , self . peek ( isAt: . integerLiteral) {
960
+ self . consumeAnyToken ( )
961
+ self . consumeAnyToken ( )
962
+ return true
963
+ }
964
+ if self . consume ( if: . integerLiteral) != nil {
965
+ return true
966
+ }
967
+ return false
968
+ }
969
+
970
+ mutating func canParseGenericArgument( ) -> Bool {
971
+ // A generic argument can either be a type or an integer literal (who is
972
+ // optionally negative).
973
+ self . canParseType ( ) || self . canParseIntegerLiteral ( )
974
+ }
975
+
866
976
mutating func consumeGenericArguments( ) -> Bool {
867
977
// Parse the opening '<'.
868
978
guard self . consume ( ifPrefix: " < " , as: . leftAngle) != nil else {
@@ -872,21 +982,9 @@ extension Parser.Lookahead {
872
982
if !self . at ( prefix: " > " ) {
873
983
var loopProgress = LoopProgressCondition ( )
874
984
repeat {
875
- // A generic argument can either be a type or an integer literal (who is
876
- // optionally negative).
877
- if self . canParseType ( ) {
878
- continue
879
- } else if self . currentToken. tokenText == " - " ,
880
- self . peek ( isAt: . integerLiteral)
881
- {
882
- self . consumeAnyToken ( )
883
- self . consumeAnyToken ( )
884
- continue
885
- } else if self . consume ( if: . integerLiteral) != nil {
886
- continue
985
+ guard self . canParseGenericArgument ( ) else {
986
+ return false
887
987
}
888
-
889
- return false
890
988
// Parse the comma, if the list continues.
891
989
} while self . consume ( if: . comma) != nil && self . hasProgressed ( & loopProgress)
892
990
}
0 commit comments