@@ -577,6 +577,11 @@ extension Parser {
577577}
578578
579579extension 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+
580585 /// Parse an array or dictionary type..
581586 mutating func parseCollectionType( ) -> RawTypeSyntax {
582587 if let remaingingTokens = remainingTokensIfMaximumNestingLevelReached ( ) {
@@ -592,6 +597,15 @@ extension Parser {
592597 }
593598
594599 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+
595609 let firstType = self . parseType ( )
596610 if let colon = self . consume ( if: . colon) {
597611 let secondType = self . parseType ( )
@@ -622,6 +636,39 @@ extension Parser {
622636 )
623637 }
624638 }
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+ }
625672}
626673
627674extension Parser . Lookahead {
@@ -714,15 +761,7 @@ extension Parser.Lookahead {
714761 }
715762 case TokenSpec ( . leftSquare) :
716763 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 {
726765 return false
727766 }
728767 case TokenSpec ( . wildcard) :
@@ -762,6 +801,59 @@ extension Parser.Lookahead {
762801 return true
763802 }
764803
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+
765857 mutating func canParseTupleBodyType( ) -> Bool {
766858 guard
767859 !self . at ( . rightParen, . rightBrace) && !self . atContextualPunctuator ( " ... " )
@@ -863,6 +955,24 @@ extension Parser.Lookahead {
863955 return lookahead. currentToken. isGenericTypeDisambiguatingToken
864956 }
865957
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+
866976 mutating func consumeGenericArguments( ) -> Bool {
867977 // Parse the opening '<'.
868978 guard self . consume ( ifPrefix: " < " , as: . leftAngle) != nil else {
@@ -872,21 +982,9 @@ extension Parser.Lookahead {
872982 if !self . at ( prefix: " > " ) {
873983 var loopProgress = LoopProgressCondition ( )
874984 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
887987 }
888-
889- return false
890988 // Parse the comma, if the list continues.
891989 } while self . consume ( if: . comma) != nil && self . hasProgressed ( & loopProgress)
892990 }
0 commit comments