@@ -687,26 +687,92 @@ extension Parser.Lookahead {
687687 return true
688688 }
689689
690- mutating func skipTypeAttributeList ( ) {
690+ mutating func canParseTypeAttributeList ( ) -> Bool {
691691 var specifierProgress = LoopProgressCondition ( )
692- // TODO: Can we model isolated/_const so that they're specified in both canParse* and parse*?
693692 while canHaveParameterSpecifier,
694- self . at ( anyIn: SimpleTypeSpecifierSyntax . SpecifierOptions. self) != nil || self . at ( . keyword ( . isolated ) )
695- || self . at ( . keyword( . _const ) ) ,
693+ self . at ( anyIn: SimpleTypeSpecifierSyntax . SpecifierOptions. self) != nil
694+ || self . at ( . keyword( . nonisolated ) , . keyword ( . dependsOn ) ) ,
696695 self . hasProgressed ( & specifierProgress)
697696 {
698- self . consumeAnyToken ( )
697+ switch self . currentToken {
698+ case . keyword( . nonisolated) :
699+ let canParseNonisolated = self . withLookahead ( {
700+ // Consume 'nonisolated'
701+ $0. consumeAnyToken ( )
702+
703+ // The argument is missing but it still could be a valid modifier,
704+ // i.e. `nonisolated` in an inheritance clause.
705+ guard $0. at ( TokenSpec ( . leftParen, allowAtStartOfLine: false ) ) else {
706+ return true
707+ }
708+
709+ // Consume '('
710+ $0. consumeAnyToken ( )
711+
712+ // nonisolated accepts a single modifier at the moment: 'nonsending'
713+ // we need to check for that explicitly to avoid misinterpreting this
714+ // keyword to be a modifier when it isn't i.e. `[nonisolated(42)]`
715+ guard $0. consume ( if: TokenSpec ( . nonsending, allowAtStartOfLine: false ) ) != nil else {
716+ return false
717+ }
718+
719+ return $0. consume ( if: TokenSpec ( . rightParen, allowAtStartOfLine: false ) ) != nil
720+ } )
721+
722+ guard canParseNonisolated else {
723+ return false
724+ }
725+
726+ self . consumeAnyToken ( )
727+
728+ guard self . at ( TokenSpec ( . leftParen, allowAtStartOfLine: false ) ) else {
729+ continue
730+ }
731+
732+ self . skipSingle ( )
733+
734+ case . keyword( . dependsOn) :
735+ let canParseDependsOn = self . withLookahead ( {
736+ // Consume 'dependsOn'
737+ $0. consumeAnyToken ( )
738+
739+ if $0. currentToken. isAtStartOfLine {
740+ return false
741+ }
742+
743+ // `dependsOn` requires an argument list.
744+ guard $0. atAttributeOrSpecifierArgument ( ) else {
745+ return false
746+ }
747+
748+ return true
749+ } )
750+
751+ guard canParseDependsOn else {
752+ return false
753+ }
754+
755+ self . consumeAnyToken ( )
756+ self . skipSingle ( )
757+
758+ default :
759+ self . consumeAnyToken ( )
760+ }
699761 }
700762
701763 var attributeProgress = LoopProgressCondition ( )
702764 while self . at ( . atSign) , self . hasProgressed ( & attributeProgress) {
703765 self . consumeAnyToken ( )
704766 self . skipTypeAttribute ( )
705767 }
768+
769+ return true
706770 }
707771
708772 mutating func canParseTypeScalar( ) -> Bool {
709- self . skipTypeAttributeList ( )
773+ guard self . canParseTypeAttributeList ( ) else {
774+ return false
775+ }
710776
711777 guard self . canParseSimpleOrCompositionType ( ) else {
712778 return false
@@ -1056,6 +1122,88 @@ extension Parser {
10561122 return . lifetimeTypeSpecifier( lifetimeSpecifier)
10571123 }
10581124
1125+ private mutating func parseNonisolatedTypeSpecifier( ) -> RawTypeSpecifierListSyntax . Element {
1126+ let ( unexpectedBeforeNonisolatedKeyword, nonisolatedKeyword) = self . expect ( . keyword( . nonisolated) )
1127+
1128+ // If the next token is not '(' this could mean two things:
1129+ // - What follows is a type and we should allow it because
1130+ // using `nonsisolated` without an argument is allowed in
1131+ // an inheritance clause.
1132+ // - The '(nonsending)' was omitted.
1133+ if !self . at ( . leftParen) {
1134+ // `nonisolated P<...>` is allowed in an inheritance clause.
1135+ if withLookahead ( { $0. canParseTypeIdentifier ( ) } ) {
1136+ let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax (
1137+ unexpectedBeforeNonisolatedKeyword,
1138+ nonisolatedKeyword: nonisolatedKeyword,
1139+ argument: nil ,
1140+ arena: self . arena
1141+ )
1142+ return . nonisolatedTypeSpecifier( nonisolatedSpecifier)
1143+ }
1144+
1145+ // Otherwise require '(nonsending)'
1146+ let argument = RawNonisolatedSpecifierArgumentSyntax (
1147+ leftParen: missingToken ( . leftParen) ,
1148+ nonsendingKeyword: missingToken ( . keyword( . nonsending) ) ,
1149+ rightParen: missingToken ( . rightParen) ,
1150+ arena: self . arena
1151+ )
1152+
1153+ let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax (
1154+ unexpectedBeforeNonisolatedKeyword,
1155+ nonisolatedKeyword: nonisolatedKeyword,
1156+ argument: argument,
1157+ arena: self . arena
1158+ )
1159+
1160+ return . nonisolatedTypeSpecifier( nonisolatedSpecifier)
1161+ }
1162+
1163+ // Avoid being to greedy about `(` since this modifier should be associated with
1164+ // function types, it's possible that the argument is omitted and what follows
1165+ // is a function type i.e. `nonisolated () async -> Void`.
1166+ if self . at ( . leftParen) && !withLookahead( { $0. atAttributeOrSpecifierArgument ( ) } ) {
1167+ let argument = RawNonisolatedSpecifierArgumentSyntax (
1168+ leftParen: missingToken ( . leftParen) ,
1169+ nonsendingKeyword: missingToken ( . keyword( . nonsending) ) ,
1170+ rightParen: missingToken ( . rightParen) ,
1171+ arena: self . arena
1172+ )
1173+
1174+ let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax (
1175+ unexpectedBeforeNonisolatedKeyword,
1176+ nonisolatedKeyword: nonisolatedKeyword,
1177+ argument: argument,
1178+ arena: self . arena
1179+ )
1180+
1181+ return . nonisolatedTypeSpecifier( nonisolatedSpecifier)
1182+ }
1183+
1184+ let ( unexpectedBeforeLeftParen, leftParen) = self . expect ( . leftParen)
1185+ let ( unexpectedBeforeModifier, modifier) = self . expect ( . keyword( . nonsending) )
1186+ let ( unexpectedBeforeRightParen, rightParen) = self . expect ( . rightParen)
1187+
1188+ let argument = RawNonisolatedSpecifierArgumentSyntax (
1189+ unexpectedBeforeLeftParen,
1190+ leftParen: leftParen,
1191+ unexpectedBeforeModifier,
1192+ nonsendingKeyword: modifier,
1193+ unexpectedBeforeRightParen,
1194+ rightParen: rightParen,
1195+ arena: self . arena
1196+ )
1197+
1198+ let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax (
1199+ unexpectedBeforeNonisolatedKeyword,
1200+ nonisolatedKeyword: nonisolatedKeyword,
1201+ argument: argument,
1202+ arena: self . arena
1203+ )
1204+ return . nonisolatedTypeSpecifier( nonisolatedSpecifier)
1205+ }
1206+
10591207 private mutating func parseSimpleTypeSpecifier(
10601208 specifierHandle: TokenConsumptionHandle
10611209 ) -> RawTypeSpecifierListSyntax . Element {
@@ -1079,6 +1227,13 @@ extension Parser {
10791227 } else {
10801228 break SPECIFIER_PARSING
10811229 }
1230+ } else if self . at ( . keyword( . nonisolated) ) {
1231+ // If '(' is located on the new line 'nonisolated' cannot be parsed
1232+ // as a specifier.
1233+ if self . peek ( isAt: . leftParen) && self . peek ( ) . isAtStartOfLine {
1234+ break SPECIFIER_PARSING
1235+ }
1236+ specifiers. append ( parseNonisolatedTypeSpecifier ( ) )
10821237 } else {
10831238 break SPECIFIER_PARSING
10841239 }
0 commit comments