diff --git a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift index 4c5a1061d4d..3ae3005bfce 100644 --- a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift @@ -120,6 +120,8 @@ public let DECL_NODES: [Node] = [ .keyword(._modify), .keyword(.modify), .keyword(.`init`), + .keyword(.borrow), + .keyword(.mutate), ]) ), Child( diff --git a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift index f14f1de8e9d..690792dad47 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift @@ -23,6 +23,7 @@ public enum ExperimentalFeature: String, CaseIterable { case oldOwnershipOperatorSpellings case defaultIsolationPerFile case moduleSelector + case borrowAndMutateAccessors /// The name of the feature as it is written in the compiler's `Features.def` file. public var featureName: String { @@ -47,6 +48,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "DefaultIsolationPerFile" case .moduleSelector: return "ModuleSelector" + case .borrowAndMutateAccessors: + return "BorrowAndMutateAccessors" } } @@ -73,6 +76,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "set default actor isolation for a file" case .moduleSelector: return "Module selector syntax (`ModName::identifier`)" + case .borrowAndMutateAccessors: + return "borrow and mutate accessors" } } diff --git a/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift b/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift index e4a66399721..2b1809ae634 100644 --- a/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift +++ b/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift @@ -201,6 +201,7 @@ public enum Keyword: CaseIterable { case metadata case modify case module + case mutate case mutableAddressWithNativeOwner case mutableAddressWithOwner case mutating @@ -535,6 +536,8 @@ public enum Keyword: CaseIterable { return KeywordSpec("modify", experimentalFeature: .coroutineAccessors) case .module: return KeywordSpec("module") + case .mutate: + return KeywordSpec("mutate", experimentalFeature: .borrowAndMutateAccessors) case .mutableAddressWithNativeOwner: return KeywordSpec("mutableAddressWithNativeOwner") case .mutableAddressWithOwner: diff --git a/Sources/SwiftParser/TokenPrecedence.swift b/Sources/SwiftParser/TokenPrecedence.swift index c0edb214bff..55dd9ffb769 100644 --- a/Sources/SwiftParser/TokenPrecedence.swift +++ b/Sources/SwiftParser/TokenPrecedence.swift @@ -239,7 +239,7 @@ enum TokenPrecedence: Comparable { .dependsOn, .scoped, .sending, // Accessors .get, .set, .didSet, .willSet, .unsafeAddress, .addressWithOwner, .addressWithNativeOwner, .unsafeMutableAddress, - .mutableAddressWithOwner, .mutableAddressWithNativeOwner, ._read, .read, ._modify, .modify, + .mutableAddressWithOwner, .mutableAddressWithNativeOwner, ._read, .read, ._modify, .modify, .mutate, // Misc .import, .using: self = .declKeyword diff --git a/Sources/SwiftParser/generated/ExperimentalFeatures.swift b/Sources/SwiftParser/generated/ExperimentalFeatures.swift index 1c12c14a148..b04cdfcd946 100644 --- a/Sources/SwiftParser/generated/ExperimentalFeatures.swift +++ b/Sources/SwiftParser/generated/ExperimentalFeatures.swift @@ -55,6 +55,9 @@ extension Parser.ExperimentalFeatures { /// Whether to enable the parsing of Module selector syntax (`ModName::identifier`). public static let moduleSelector = Self (rawValue: 1 << 9) + /// Whether to enable the parsing of borrow and mutate accessors. + public static let borrowAndMutateAccessors = Self (rawValue: 1 << 10) + /// Creates a new value representing the experimental feature with the /// given name, or returns nil if the name is not recognized. public init?(name: String) { @@ -79,6 +82,8 @@ extension Parser.ExperimentalFeatures { self = .defaultIsolationPerFile case "ModuleSelector": self = .moduleSelector + case "BorrowAndMutateAccessors": + self = .borrowAndMutateAccessors default: return nil } diff --git a/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift b/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift index ecc4bea5e93..92d9b8d96a4 100644 --- a/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift +++ b/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift @@ -39,6 +39,9 @@ extension AccessorDeclSyntax { @_spi(ExperimentalLanguageFeatures) case modify case `init` + case borrow + @_spi(ExperimentalLanguageFeatures) + case mutate init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) { switch PrepareForKeywordMatch(lexeme) { @@ -72,6 +75,10 @@ extension AccessorDeclSyntax { self = .modify case TokenSpec(.`init`): self = .`init` + case TokenSpec(.borrow): + self = .borrow + case TokenSpec(.mutate) where experimentalFeatures.contains(.borrowAndMutateAccessors): + self = .mutate default: return nil } @@ -109,6 +116,10 @@ extension AccessorDeclSyntax { self = .modify case TokenSpec(.`init`): self = .`init` + case TokenSpec(.borrow): + self = .borrow + case TokenSpec(.mutate): + self = .mutate default: return nil } @@ -146,6 +157,10 @@ extension AccessorDeclSyntax { return .keyword(.modify) case .`init`: return .keyword(.`init`) + case .borrow: + return .keyword(.borrow) + case .mutate: + return .keyword(.mutate) } } @@ -185,6 +200,10 @@ extension AccessorDeclSyntax { return .keyword(.modify) case .`init`: return .keyword(.`init`) + case .borrow: + return .keyword(.borrow) + case .mutate: + return .keyword(.mutate) } } } diff --git a/Sources/SwiftSyntax/generated/Keyword.swift b/Sources/SwiftSyntax/generated/Keyword.swift index 61e59e93cbc..f557d35d503 100644 --- a/Sources/SwiftSyntax/generated/Keyword.swift +++ b/Sources/SwiftSyntax/generated/Keyword.swift @@ -145,6 +145,8 @@ public enum Keyword: UInt8, Hashable, Sendable { @_spi(ExperimentalLanguageFeatures) case modify case module + @_spi(ExperimentalLanguageFeatures) + case mutate case mutableAddressWithNativeOwner case mutableAddressWithOwner case mutating @@ -403,6 +405,8 @@ public enum Keyword: UInt8, Hashable, Sendable { self = .modify case "module": self = .module + case "mutate": + self = .mutate case "prefix": self = .prefix case "public": @@ -883,6 +887,7 @@ public enum Keyword: UInt8, Hashable, Sendable { "metadata", "modify", "module", + "mutate", "mutableAddressWithNativeOwner", "mutableAddressWithOwner", "mutating", diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index a768f46192f..437ec0f5d05 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -264,7 +264,9 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { .keyword("read"), .keyword("_modify"), .keyword("modify"), - .keyword("init") + .keyword("init"), + .keyword("borrow"), + .keyword("mutate") ])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 7, verify(layout[7], as: RawAccessorParametersSyntax?.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift index 4e07265bc4a..d59177a6260 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift @@ -825,7 +825,7 @@ public struct AccessorBlockSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNo /// /// - `attributes`: ``AttributeListSyntax`` /// - `modifier`: ``DeclModifierSyntax``? -/// - `accessorSpecifier`: (`get` | `set` | `didSet` | `willSet` | `unsafeAddress` | `addressWithOwner` | `addressWithNativeOwner` | `unsafeMutableAddress` | `mutableAddressWithOwner` | `mutableAddressWithNativeOwner` | `_read` | `read` | `_modify` | `modify` | `init`) +/// - `accessorSpecifier`: (`get` | `set` | `didSet` | `willSet` | `unsafeAddress` | `addressWithOwner` | `addressWithNativeOwner` | `unsafeMutableAddress` | `mutableAddressWithOwner` | `mutableAddressWithNativeOwner` | `_read` | `read` | `_modify` | `modify` | `init` | `borrow` | `mutate`) /// - `parameters`: ``AccessorParametersSyntax``? /// - `effectSpecifiers`: ``AccessorEffectSpecifiersSyntax``? /// - `body`: ``CodeBlockSyntax``? @@ -1001,6 +1001,8 @@ public struct AccessorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable, _LeafDeclS /// - `_modify` /// - `modify` /// - `init` + /// - `borrow` + /// - `mutate` public var accessorSpecifier: TokenSyntax { get { return Syntax(self).child(at: 5)!.cast(TokenSyntax.self) diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index d72f00824b1..dfce19135e3 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -3473,6 +3473,28 @@ final class DeclarationTests: ParserTestCase { ) } + func testBorrowAndMutateAccessors() { + assertParse( + """ + public class Klass {} + + public struct Wrapper { + var _otherK: Klass + + var k1: Klass { + borrow { + return _otherK + } + mutate { + return &_otherK + } + } + } + """, + experimentalFeatures: .borrowAndMutateAccessors + ) + } + func testMissingCommaInParameters() { assertParse( "func a(foo: Bar1️⃣ foo2: Bar2) {}",