Skip to content

Commit 0360a0d

Browse files
committed
[SwiftParser] Allow nonisolated to accept nonsending modifier
1 parent 09ea403 commit 0360a0d

File tree

5 files changed

+61
-1
lines changed

5 files changed

+61
-1
lines changed

CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ public enum Keyword: CaseIterable {
210210
case none
211211
case nonisolated
212212
case nonmutating
213+
case nonsending
213214
case objc
214215
case obsoleted
215216
case of
@@ -551,6 +552,8 @@ public enum Keyword: CaseIterable {
551552
return KeywordSpec("nonisolated")
552553
case .nonmutating:
553554
return KeywordSpec("nonmutating")
555+
case .nonsending:
556+
return KeywordSpec("nonsending")
554557
case .objc:
555558
return KeywordSpec("objc")
556559
case .obsoleted:

Sources/SwiftParser/Modifiers.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,35 @@ extension Parser {
231231
}
232232

233233
mutating func parseNonisolatedModifier(_ handle: RecoveryConsumptionHandle) -> RawDeclModifierSyntax {
234+
enum NonIsolatedModifier: TokenSpecSet {
235+
case unsafe
236+
case nonsending
237+
238+
var spec: TokenSpec {
239+
switch self {
240+
case .unsafe: return .keyword(.unsafe)
241+
case .nonsending: return .keyword(.nonsending)
242+
}
243+
}
244+
245+
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
246+
switch PrepareForKeywordMatch(lexeme) {
247+
case TokenSpec(.unsafe): self = .unsafe
248+
case TokenSpec(.nonsending): self = .nonsending
249+
default: return nil
250+
}
251+
}
252+
}
253+
234254
let (unexpectedBeforeKeyword, keyword) = self.eat(handle)
235255

236256
let detail: RawDeclModifierDetailSyntax?
237257
if self.at(.leftParen) {
238258
let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
239-
let (unexpectedBeforeDetailToken, detailToken) = self.expect(TokenSpec(.unsafe, remapping: .identifier))
259+
let (unexpectedBeforeDetailToken, detailToken) = self.expect(
260+
anyIn: NonIsolatedModifier.self,
261+
default: .unsafe
262+
)
240263
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
241264
detail = RawDeclModifierDetailSyntax(
242265
unexpectedBeforeLeftParen,

Sources/SwiftParser/TokenPrecedence.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ enum TokenPrecedence: Comparable {
326326
.module,
327327
.noasync,
328328
.none,
329+
.nonsending,
329330
.obsoleted,
330331
.of,
331332
.Protocol,

Sources/SwiftSyntax/generated/Keyword.swift

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,35 @@ final class DeclarationTests: ParserTestCase {
277277
)
278278
}
279279

280+
func testNonisolatedNonSendingParsing() {
281+
assertParse(
282+
"""
283+
nonisolated(nonsending) let a = 0
284+
285+
struct A {
286+
nonisolated(nonsending) let b = 0
287+
nonisolated(nonsending) var c: Int { 0 }
288+
nonisolated(1️⃣sending) let d = 0
289+
}
290+
""",
291+
diagnostics: [
292+
DiagnosticSpec(
293+
message: "expected 'unsafe' in modifier",
294+
fixIts: ["replace 'sending' with 'unsafe'"]
295+
)
296+
],
297+
fixedSource: """
298+
nonisolated(nonsending) let a = 0
299+
300+
struct A {
301+
nonisolated(nonsending) let b = 0
302+
nonisolated(nonsending) var c: Int { 0 }
303+
nonisolated(unsafe) let d = 0
304+
}
305+
"""
306+
)
307+
}
308+
280309
func testProtocolParsing() {
281310
assertParse("protocol Foo {}")
282311

0 commit comments

Comments
 (0)