Skip to content
Open
3 changes: 3 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ public enum Keyword: CaseIterable {
case willSet
case wrt
case yield
case yielding

public var spec: KeywordSpec {
switch self {
Expand Down Expand Up @@ -692,6 +693,8 @@ public enum Keyword: CaseIterable {
return KeywordSpec("wrt")
case .yield:
return KeywordSpec("yield")
case .yielding:
return KeywordSpec("yielding")
}
}
}
24 changes: 23 additions & 1 deletion Sources/SwiftParser/Declarations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1671,9 +1671,14 @@ extension Parser {
var look = self.lookahead()
let _ = look.consumeAttributeList()
let hasModifier = look.consume(ifAnyIn: AccessorModifier.self) != nil
let yielding = look.consume(if: TokenSpec(.yielding)) != nil
guard let (kind, _) = look.at(anyIn: AccessorDeclSyntax.AccessorSpecifierOptions.self) ?? forcedKind else {
return nil
}
guard !yielding || [AccessorDeclSyntax.AccessorSpecifierOptions.borrow, .mutate].contains(kind) else {
// `yielding` can only be followed by `borrow` or `mutate`
return nil
}

let attrs = self.parseAttributeList()

Expand All @@ -1692,11 +1697,28 @@ extension Parser {
modifier = nil
}

if yielding {
_ = self.expect(TokenSpec(.yielding))
}

let (unexpectedBeforeIntroducer, introducer) = self.expect(kind.spec)

// Map `yielding borrow` => `read`, etc.
Copy link
Author

@tbkka tbkka Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks round-tripping, so I can't do this mapping here.

let resolvedKind: AccessorDeclSyntax.AccessorSpecifierOptions
if yielding {
switch kind {
case .borrow: resolvedKind = .read // `yielding borrow` == `read`
case .mutate: resolvedKind = .modify // `yielding mutate` == `modify`
default: resolvedKind = kind
}
} else {
resolvedKind = kind
}

return AccessorIntroducer(
attributes: attrs,
modifier: modifier,
kind: kind,
kind: resolvedKind,
unexpectedBeforeToken: unexpectedBeforeIntroducer,
token: introducer
)
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftParser/TokenPrecedence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ enum TokenPrecedence: Comparable {
.dependsOn, .scoped, .sending,
// Accessors
.get, .set, .didSet, .willSet, .unsafeAddress, .addressWithOwner, .addressWithNativeOwner, .unsafeMutableAddress,
.mutableAddressWithOwner, .mutableAddressWithNativeOwner, ._read, .read, ._modify, .modify, .mutate,
.mutableAddressWithOwner, .mutableAddressWithNativeOwner, ._read, .read, ._modify, .modify, .mutate, .yielding,
// Misc
.import, .using:
self = .declKeyword
Expand Down
4 changes: 4 additions & 0 deletions Sources/SwiftSyntax/generated/Keyword.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Tests/SwiftParserTest/DeclarationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3467,12 +3467,18 @@ final class DeclarationTests: ParserTestCase {
read {
yield _i
}
yielding borrow {
yield _i
}
_modify {
yield &_i
}
modify {
yield &_i
}
yielding mutate {
yield &_i
}
}
""",
experimentalFeatures: .coroutineAccessors
Expand Down
Loading