diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 00000000000..b260e72b4ed --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,17 @@ +name: Create PR to merge main into release branch +# In the first period after branching the release branch, we typically want to include many changes from `main` in the release branch. This workflow automatically creates a PR every Monday to merge main into the release branch. +# Later in the release cycle we should stop this practice to avoid landing risky changes by disabling this workflow. To do so, disable the workflow as described in https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow +on: + schedule: + - cron: '0 9 * * MON' + workflow_dispatch: +jobs: + create_merge_pr: + name: Create PR to merge main into release branch + uses: swiftlang/github-workflows/.github/workflows/create_automerge_pr.yml@main + with: + base_branch: release/6.2 + permissions: + contents: write + pull-requests: write + if: (github.event_name == 'schedule' && github.repository == 'swiftlang/swift-syntax') || (github.event_name != 'schedule') # Ensure that we don't run this on a schedule in a fork diff --git a/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift b/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift index 2cf01f217b0..7c4b72eeafb 100644 --- a/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift +++ b/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift @@ -210,6 +210,7 @@ public enum Keyword: CaseIterable { case none case nonisolated case nonmutating + case nonsending case objc case obsoleted case of @@ -551,6 +552,8 @@ public enum Keyword: CaseIterable { return KeywordSpec("nonisolated") case .nonmutating: return KeywordSpec("nonmutating") + case .nonsending: + return KeywordSpec("nonsending") case .objc: return KeywordSpec("objc") case .obsoleted: diff --git a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift index ab07a05f470..6e50fe39500 100644 --- a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift +++ b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift @@ -210,6 +210,9 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon case multipleTrailingClosureElementList case namedOpaqueReturnType case nilLiteralExpr + case nonisolatedSpecifierArgument + case nonisolatedSpecifierArgumentList + case nonisolatedTypeSpecifier case objCSelectorPiece case objCSelectorPieceList case operatorDecl diff --git a/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift b/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift index 9b9aa3c6e1e..3d65755fa45 100644 --- a/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift @@ -676,6 +676,52 @@ public let TYPE_NODES: [Node] = [ ] ), + Node( + kind: .nonisolatedSpecifierArgument, + base: .syntax, + nameForDiagnostics: nil, + documentation: """ + A single argument that can be added to a nonisolated specifier: 'nonsending'. + + ### Example + `data` in `func foo(data: nonisolated(nonsending) () async -> Void) -> X` + """, + traits: [ + "Parenthesized" + ], + children: [ + Child( + name: "leftParen", + kind: .token(choices: [.token(.leftParen)]) + ), + Child( + name: "nonsendingKeyword", + kind: .token(choices: [.keyword(.nonsending)]) + ), + Child( + name: "rightParen", + kind: .token(choices: [.token(.rightParen)]) + ), + ] + ), + + Node( + kind: .nonisolatedTypeSpecifier, + base: .syntax, + nameForDiagnostics: "'nonisolated' specifier", + children: [ + Child( + name: "nonisolatedKeyword", + kind: .token(choices: [.keyword(.nonisolated)]) + ), + Child( + name: "argument", + kind: .node(kind: .nonisolatedSpecifierArgument), + isOptional: true + ), + ] + ), + Node( kind: .simpleTypeSpecifier, base: .syntax, @@ -689,7 +735,6 @@ public let TYPE_NODES: [Node] = [ .keyword(.__shared), .keyword(.__owned), .keyword(.isolated), - .keyword(.nonisolated), .keyword(._const), .keyword(.borrowing), .keyword(.consuming), @@ -704,6 +749,6 @@ public let TYPE_NODES: [Node] = [ kind: .typeSpecifierList, base: .syntaxCollection, nameForDiagnostics: nil, - elementChoices: [.simpleTypeSpecifier, .lifetimeTypeSpecifier] + elementChoices: [.simpleTypeSpecifier, .lifetimeTypeSpecifier, .nonisolatedTypeSpecifier] ), ] diff --git a/Release Notes/602.md b/Release Notes/602.md index 12c16b08703..0d5750bdd2e 100644 --- a/Release Notes/602.md +++ b/Release Notes/602.md @@ -12,6 +12,11 @@ - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2981 - Migration steps: None required. The new `category` property has optional type, and there is a default implementation that returns `nil`. Types that conform to `DiagnosticMessage` can choose to implement this property and provide a category when appropriate. +- `DiagnosticsFormatter` has a new method, `formattedMessage`, that formats a diagnostic message without any corresponding syntax node. + - Description: Some tools want to use the diagnostics formatter to produce diagnostics that don't relate to source code, or for which the source code isn't available. This API allows them to do so while maintaining consistent presentation. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/3059 + - Migration steps: None required. + - `FixIt.Change` has a new case `replaceText` that performs a textual replacement of a range of text with another string. - Description: The other `FixIt.Change` cases provide structured modifications to syntax trees, such as replacing specific notes. Some diff --git a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift index 9717ecb4ac7..e93bc1d609f 100644 --- a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -360,6 +360,12 @@ public struct DiagnosticsFormatter { ) } + /// Produce a string that formats the given diagnostic message with any + /// source-location information. + public func formattedMessage(_ message: some DiagnosticMessage) -> String { + diagnosticDecorator.decorateDiagnosticMessage(message) + } + /// Produce a string containing "footnotes" for each of the diagnostic /// category provided that has associated documentation. Each category /// is printed in Markdown link format, e.g., diff --git a/Sources/SwiftParser/Attributes.swift b/Sources/SwiftParser/Attributes.swift index 72af60d312c..2f066fd6c39 100644 --- a/Sources/SwiftParser/Attributes.swift +++ b/Sources/SwiftParser/Attributes.swift @@ -157,7 +157,7 @@ extension Parser { shouldParseArgument = true case .customAttribute: shouldParseArgument = - self.withLookahead { $0.atCustomAttributeArgument() } + self.withLookahead { $0.atAttributeOrSpecifierArgument() } && self.at(TokenSpec(.leftParen, allowAtStartOfLine: false)) case .optional: shouldParseArgument = self.at(.leftParen) @@ -1002,7 +1002,7 @@ extension Parser { // MARK: Lookahead extension Parser.Lookahead { - mutating func atCustomAttributeArgument() -> Bool { + mutating func atAttributeOrSpecifierArgument() -> Bool { var lookahead = self.lookahead() lookahead.skipSingle() @@ -1036,7 +1036,7 @@ extension Parser.Lookahead { } if self.at(TokenSpec(.leftParen, allowAtStartOfLine: false)) - && self.withLookahead({ $0.atCustomAttributeArgument() }) + && self.withLookahead({ $0.atAttributeOrSpecifierArgument() }) { self.skipSingle() } diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 11bcdf4ee1a..70e2a433f56 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -381,13 +381,39 @@ extension Parser { } } + /// Make sure that we only accept `nonisolated(nonsending)` as a valid type specifier + /// in expression context to minimize source compatibility impact. + func canParseNonisolatedAsSpecifierInExpressionContext() -> Bool { + return withLookahead { + guard $0.consume(if: .keyword(.nonisolated)) != nil else { + return false + } + + if $0.currentToken.isAtStartOfLine { + return false + } + + guard $0.consume(if: .leftParen) != nil else { + return false + } + + guard $0.consume(if: TokenSpec(.nonsending, allowAtStartOfLine: false)) != nil else { + return false + } + + return $0.at(TokenSpec(.rightParen, allowAtStartOfLine: false)) + } + } + /// Parse an expression sequence element. mutating func parseSequenceExpressionElement( flavor: ExprFlavor, pattern: PatternContext = .none ) -> RawExprSyntax { - // Try to parse '@' sign or 'inout' as an attributed typerepr. - if self.at(.atSign, .keyword(.inout)) { + // Try to parse '@' sign, 'inout', or 'nonisolated' as an attributed typerepr. + if self.at(.atSign, .keyword(.inout)) + || self.canParseNonisolatedAsSpecifierInExpressionContext() + { var lookahead = self.lookahead() if lookahead.canParseType() { let type = self.parseType() diff --git a/Sources/SwiftParser/Modifiers.swift b/Sources/SwiftParser/Modifiers.swift index 73a6066a9cf..57ef2b302ae 100644 --- a/Sources/SwiftParser/Modifiers.swift +++ b/Sources/SwiftParser/Modifiers.swift @@ -236,7 +236,11 @@ extension Parser { let detail: RawDeclModifierDetailSyntax? if self.at(.leftParen) { let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen) - let (unexpectedBeforeDetailToken, detailToken) = self.expect(TokenSpec(.unsafe, remapping: .identifier)) + let (unexpectedBeforeDetailToken, detailToken) = self.expect( + TokenSpec(.unsafe, remapping: .identifier), + TokenSpec(.nonsending, remapping: .identifier), + default: TokenSpec(.identifier) + ) let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen) detail = RawDeclModifierDetailSyntax( unexpectedBeforeLeftParen, diff --git a/Sources/SwiftParser/TokenPrecedence.swift b/Sources/SwiftParser/TokenPrecedence.swift index 39784f5d2aa..01fdbc06f78 100644 --- a/Sources/SwiftParser/TokenPrecedence.swift +++ b/Sources/SwiftParser/TokenPrecedence.swift @@ -326,6 +326,7 @@ enum TokenPrecedence: Comparable { .module, .noasync, .none, + .nonsending, .obsoleted, .of, .Protocol, diff --git a/Sources/SwiftParser/Types.swift b/Sources/SwiftParser/Types.swift index 373788f7d73..416f06ddc1f 100644 --- a/Sources/SwiftParser/Types.swift +++ b/Sources/SwiftParser/Types.swift @@ -687,15 +687,77 @@ extension Parser.Lookahead { return true } - mutating func skipTypeAttributeList() { + mutating func canParseTypeAttributeList() -> Bool { var specifierProgress = LoopProgressCondition() - // TODO: Can we model isolated/_const so that they're specified in both canParse* and parse*? while canHaveParameterSpecifier, - self.at(anyIn: SimpleTypeSpecifierSyntax.SpecifierOptions.self) != nil || self.at(.keyword(.isolated)) - || self.at(.keyword(._const)), + self.at(anyIn: SimpleTypeSpecifierSyntax.SpecifierOptions.self) != nil + || self.at(.keyword(.nonisolated), .keyword(.dependsOn)), self.hasProgressed(&specifierProgress) { - self.consumeAnyToken() + switch self.currentToken { + case .keyword(.nonisolated): + let canParseNonisolated = self.withLookahead({ + // Consume 'nonisolated' + $0.consumeAnyToken() + + // The argument is missing but it still could be a valid modifier, + // i.e. `nonisolated` in an inheritance clause. + guard $0.at(TokenSpec(.leftParen, allowAtStartOfLine: false)) else { + return true + } + + // Consume '(' + $0.consumeAnyToken() + + // nonisolated accepts a single modifier at the moment: 'nonsending' + // we need to check for that explicitly to avoid misinterpreting this + // keyword to be a modifier when it isn't i.e. `[nonisolated(42)]` + guard $0.consume(if: TokenSpec(.nonsending, allowAtStartOfLine: false)) != nil else { + return false + } + + return $0.consume(if: TokenSpec(.rightParen, allowAtStartOfLine: false)) != nil + }) + + guard canParseNonisolated else { + return false + } + + self.consumeAnyToken() + + guard self.at(TokenSpec(.leftParen, allowAtStartOfLine: false)) else { + continue + } + + self.skipSingle() + + case .keyword(.dependsOn): + let canParseDependsOn = self.withLookahead({ + // Consume 'dependsOn' + $0.consumeAnyToken() + + if $0.currentToken.isAtStartOfLine { + return false + } + + // `dependsOn` requires an argument list. + guard $0.atAttributeOrSpecifierArgument() else { + return false + } + + return true + }) + + guard canParseDependsOn else { + return false + } + + self.consumeAnyToken() + self.skipSingle() + + default: + self.consumeAnyToken() + } } var attributeProgress = LoopProgressCondition() @@ -703,10 +765,14 @@ extension Parser.Lookahead { self.consumeAnyToken() self.skipTypeAttribute() } + + return true } mutating func canParseTypeScalar() -> Bool { - self.skipTypeAttributeList() + guard self.canParseTypeAttributeList() else { + return false + } guard self.canParseSimpleOrCompositionType() else { return false @@ -1056,6 +1122,88 @@ extension Parser { return .lifetimeTypeSpecifier(lifetimeSpecifier) } + private mutating func parseNonisolatedTypeSpecifier() -> RawTypeSpecifierListSyntax.Element { + let (unexpectedBeforeNonisolatedKeyword, nonisolatedKeyword) = self.expect(.keyword(.nonisolated)) + + // If the next token is not '(' this could mean two things: + // - What follows is a type and we should allow it because + // using `nonsisolated` without an argument is allowed in + // an inheritance clause. + // - The '(nonsending)' was omitted. + if !self.at(.leftParen) { + // `nonisolated P<...>` is allowed in an inheritance clause. + if withLookahead({ $0.canParseTypeIdentifier() }) { + let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax( + unexpectedBeforeNonisolatedKeyword, + nonisolatedKeyword: nonisolatedKeyword, + argument: nil, + arena: self.arena + ) + return .nonisolatedTypeSpecifier(nonisolatedSpecifier) + } + + // Otherwise require '(nonsending)' + let argument = RawNonisolatedSpecifierArgumentSyntax( + leftParen: missingToken(.leftParen), + nonsendingKeyword: missingToken(.keyword(.nonsending)), + rightParen: missingToken(.rightParen), + arena: self.arena + ) + + let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax( + unexpectedBeforeNonisolatedKeyword, + nonisolatedKeyword: nonisolatedKeyword, + argument: argument, + arena: self.arena + ) + + return .nonisolatedTypeSpecifier(nonisolatedSpecifier) + } + + // Avoid being to greedy about `(` since this modifier should be associated with + // function types, it's possible that the argument is omitted and what follows + // is a function type i.e. `nonisolated () async -> Void`. + if self.at(.leftParen) && !withLookahead({ $0.atAttributeOrSpecifierArgument() }) { + let argument = RawNonisolatedSpecifierArgumentSyntax( + leftParen: missingToken(.leftParen), + nonsendingKeyword: missingToken(.keyword(.nonsending)), + rightParen: missingToken(.rightParen), + arena: self.arena + ) + + let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax( + unexpectedBeforeNonisolatedKeyword, + nonisolatedKeyword: nonisolatedKeyword, + argument: argument, + arena: self.arena + ) + + return .nonisolatedTypeSpecifier(nonisolatedSpecifier) + } + + let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen) + let (unexpectedBeforeModifier, modifier) = self.expect(.keyword(.nonsending)) + let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen) + + let argument = RawNonisolatedSpecifierArgumentSyntax( + unexpectedBeforeLeftParen, + leftParen: leftParen, + unexpectedBeforeModifier, + nonsendingKeyword: modifier, + unexpectedBeforeRightParen, + rightParen: rightParen, + arena: self.arena + ) + + let nonisolatedSpecifier = RawNonisolatedTypeSpecifierSyntax( + unexpectedBeforeNonisolatedKeyword, + nonisolatedKeyword: nonisolatedKeyword, + argument: argument, + arena: self.arena + ) + return .nonisolatedTypeSpecifier(nonisolatedSpecifier) + } + private mutating func parseSimpleTypeSpecifier( specifierHandle: TokenConsumptionHandle ) -> RawTypeSpecifierListSyntax.Element { @@ -1079,6 +1227,13 @@ extension Parser { } else { break SPECIFIER_PARSING } + } else if self.at(.keyword(.nonisolated)) { + // If '(' is located on the new line 'nonisolated' cannot be parsed + // as a specifier. + if self.peek(isAt: .leftParen) && self.peek().isAtStartOfLine { + break SPECIFIER_PARSING + } + specifiers.append(parseNonisolatedTypeSpecifier()) } else { break SPECIFIER_PARSING } diff --git a/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift b/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift index 1aaa0d9c734..bcdb11f0b95 100644 --- a/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift +++ b/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift @@ -3503,7 +3503,6 @@ extension SimpleTypeSpecifierSyntax { case __shared case __owned case isolated - case nonisolated case _const case borrowing case consuming @@ -3519,8 +3518,6 @@ extension SimpleTypeSpecifierSyntax { self = .__owned case TokenSpec(.isolated): self = .isolated - case TokenSpec(.nonisolated): - self = .nonisolated case TokenSpec(._const): self = ._const case TokenSpec(.borrowing): @@ -3544,8 +3541,6 @@ extension SimpleTypeSpecifierSyntax { self = .__owned case TokenSpec(.isolated): self = .isolated - case TokenSpec(.nonisolated): - self = .nonisolated case TokenSpec(._const): self = ._const case TokenSpec(.borrowing): @@ -3569,8 +3564,6 @@ extension SimpleTypeSpecifierSyntax { return .keyword(.__owned) case .isolated: return .keyword(.isolated) - case .nonisolated: - return .keyword(.nonisolated) case ._const: return .keyword(._const) case .borrowing: @@ -3596,8 +3589,6 @@ extension SimpleTypeSpecifierSyntax { return .keyword(.__owned) case .isolated: return .keyword(.isolated) - case .nonisolated: - return .keyword(.nonisolated) case ._const: return .keyword(._const) case .borrowing: diff --git a/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift b/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift index 07fb77669b2..3dc0aa8e82b 100644 --- a/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift +++ b/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift @@ -212,6 +212,7 @@ extension TypeSpecifierListSyntax { switch specifier { case .simpleTypeSpecifier(let specifier): return specifier.specifier case .lifetimeTypeSpecifier: return nil + case .nonisolatedTypeSpecifier: return nil #if RESILIENT_LIBRARIES @unknown default: fatalError() diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index a5afdfbf444..9a9d00393e7 100644 --- a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift @@ -294,6 +294,8 @@ extension SyntaxKind { return "trailing closure" case .namedOpaqueReturnType: return "named opaque return type" + case .nonisolatedTypeSpecifier: + return "'nonisolated' specifier" case .objCSelectorPieceList: return "Objective-C selector" case .objCSelectorPiece: diff --git a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md index 6d74ef33dcb..4ec126dbe4f 100644 --- a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md +++ b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md @@ -294,6 +294,7 @@ allows Swift tools to parse, inspect, generate, and transform Swift source code. - - - +- - - - @@ -357,6 +358,7 @@ allows Swift tools to parse, inspect, generate, and transform Swift source code. - - - +- - - - diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index 4f0645c8267..802b6ae8003 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -2370,6 +2370,30 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "nilKeyword" case \NilLiteralExprSyntax.unexpectedAfterNilKeyword: return "unexpectedAfterNilKeyword" + case \NonisolatedSpecifierArgumentSyntax.unexpectedBeforeLeftParen: + return "unexpectedBeforeLeftParen" + case \NonisolatedSpecifierArgumentSyntax.leftParen: + return "leftParen" + case \NonisolatedSpecifierArgumentSyntax.unexpectedBetweenLeftParenAndNonsendingKeyword: + return "unexpectedBetweenLeftParenAndNonsendingKeyword" + case \NonisolatedSpecifierArgumentSyntax.nonsendingKeyword: + return "nonsendingKeyword" + case \NonisolatedSpecifierArgumentSyntax.unexpectedBetweenNonsendingKeywordAndRightParen: + return "unexpectedBetweenNonsendingKeywordAndRightParen" + case \NonisolatedSpecifierArgumentSyntax.rightParen: + return "rightParen" + case \NonisolatedSpecifierArgumentSyntax.unexpectedAfterRightParen: + return "unexpectedAfterRightParen" + case \NonisolatedTypeSpecifierSyntax.unexpectedBeforeNonisolatedKeyword: + return "unexpectedBeforeNonisolatedKeyword" + case \NonisolatedTypeSpecifierSyntax.nonisolatedKeyword: + return "nonisolatedKeyword" + case \NonisolatedTypeSpecifierSyntax.unexpectedBetweenNonisolatedKeywordAndArgument: + return "unexpectedBetweenNonisolatedKeywordAndArgument" + case \NonisolatedTypeSpecifierSyntax.argument: + return "argument" + case \NonisolatedTypeSpecifierSyntax.unexpectedAfterArgument: + return "unexpectedAfterArgument" case \ObjCSelectorPieceSyntax.unexpectedBeforeName: return "unexpectedBeforeName" case \ObjCSelectorPieceSyntax.name: diff --git a/Sources/SwiftSyntax/generated/Keyword.swift b/Sources/SwiftSyntax/generated/Keyword.swift index 2abff52c6f4..20b36ff1455 100644 --- a/Sources/SwiftSyntax/generated/Keyword.swift +++ b/Sources/SwiftSyntax/generated/Keyword.swift @@ -155,6 +155,7 @@ public enum Keyword: UInt8, Hashable, Sendable { case none case nonisolated case nonmutating + case nonsending case objc case obsoleted case of @@ -584,6 +585,8 @@ public enum Keyword: UInt8, Hashable, Sendable { self = .higherThan case "introduced": self = .introduced + case "nonsending": + self = .nonsending case "visibility": self = .visibility default: @@ -893,6 +896,7 @@ public enum Keyword: UInt8, Hashable, Sendable { "none", "nonisolated", "nonmutating", + "nonsending", "objc", "obsoleted", "of", diff --git a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift index a48aab9ea71..124561440e0 100644 --- a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift @@ -1585,6 +1585,22 @@ open class SyntaxAnyVisitor: SyntaxVisitor { visitAnyPost(node._syntaxNode) } + override open func visit(_ node: NonisolatedSpecifierArgumentSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + override open func visitPost(_ node: NonisolatedSpecifierArgumentSyntax) { + visitAnyPost(node._syntaxNode) + } + + override open func visit(_ node: NonisolatedTypeSpecifierSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + override open func visitPost(_ node: NonisolatedTypeSpecifierSyntax) { + visitAnyPost(node._syntaxNode) + } + override open func visit(_ node: ObjCSelectorPieceListSyntax) -> SyntaxVisitorContinueKind { return visitAny(node._syntaxNode) } diff --git a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift index 89d739db3ed..8c1a8444f88 100644 --- a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift +++ b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift @@ -1699,6 +1699,8 @@ extension Syntax { .node(MultipleTrailingClosureElementSyntax.self), .node(NamedOpaqueReturnTypeSyntax.self), .node(NilLiteralExprSyntax.self), + .node(NonisolatedSpecifierArgumentSyntax.self), + .node(NonisolatedTypeSpecifierSyntax.self), .node(ObjCSelectorPieceListSyntax.self), .node(ObjCSelectorPieceSyntax.self), .node(OperatorDeclSyntax.self), diff --git a/Sources/SwiftSyntax/generated/SyntaxCollections.swift b/Sources/SwiftSyntax/generated/SyntaxCollections.swift index 05305c97829..a34717855b7 100644 --- a/Sources/SwiftSyntax/generated/SyntaxCollections.swift +++ b/Sources/SwiftSyntax/generated/SyntaxCollections.swift @@ -1913,7 +1913,7 @@ public struct TupleTypeElementListSyntax: SyntaxCollection, SyntaxHashable { /// ### Children /// -/// (``SimpleTypeSpecifierSyntax`` | `LifetimeTypeSpecifierSyntax`) `*` +/// (``SimpleTypeSpecifierSyntax`` | `LifetimeTypeSpecifierSyntax` | ``NonisolatedTypeSpecifierSyntax``) `*` /// /// ### Contained in /// @@ -1926,6 +1926,7 @@ public struct TypeSpecifierListSyntax: SyntaxCollection, SyntaxHashable { /// - Note: Requires experimental feature `nonescapableTypes`. @_spi(ExperimentalLanguageFeatures) case lifetimeTypeSpecifier(LifetimeTypeSpecifierSyntax) + case nonisolatedTypeSpecifier(NonisolatedTypeSpecifierSyntax) public var _syntaxNode: Syntax { switch self { @@ -1933,6 +1934,8 @@ public struct TypeSpecifierListSyntax: SyntaxCollection, SyntaxHashable { return node._syntaxNode case .lifetimeTypeSpecifier(let node): return node._syntaxNode + case .nonisolatedTypeSpecifier(let node): + return node._syntaxNode } } @@ -1946,18 +1949,24 @@ public struct TypeSpecifierListSyntax: SyntaxCollection, SyntaxHashable { self = .lifetimeTypeSpecifier(node) } + public init(_ node: NonisolatedTypeSpecifierSyntax) { + self = .nonisolatedTypeSpecifier(node) + } + public init?(_ node: __shared some SyntaxProtocol) { if let node = node.as(SimpleTypeSpecifierSyntax.self) { self = .simpleTypeSpecifier(node) } else if let node = node.as(LifetimeTypeSpecifierSyntax.self) { self = .lifetimeTypeSpecifier(node) + } else if let node = node.as(NonisolatedTypeSpecifierSyntax.self) { + self = .nonisolatedTypeSpecifier(node) } else { return nil } } public static var structure: SyntaxNodeStructure { - return .choices([.node(SimpleTypeSpecifierSyntax.self), .node(LifetimeTypeSpecifierSyntax.self)]) + return .choices([.node(SimpleTypeSpecifierSyntax.self), .node(LifetimeTypeSpecifierSyntax.self), .node(NonisolatedTypeSpecifierSyntax.self)]) } /// Checks if the current syntax node can be cast to ``SimpleTypeSpecifierSyntax``. @@ -2009,6 +2018,28 @@ public struct TypeSpecifierListSyntax: SyntaxCollection, SyntaxHashable { public func cast(_ syntaxType: LifetimeTypeSpecifierSyntax.Type) -> LifetimeTypeSpecifierSyntax { return self.as(LifetimeTypeSpecifierSyntax.self)! } + + /// Checks if the current syntax node can be cast to ``NonisolatedTypeSpecifierSyntax``. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + public func `is`(_ syntaxType: NonisolatedTypeSpecifierSyntax.Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to ``NonisolatedTypeSpecifierSyntax``. + /// + /// - Returns: An instance of ``NonisolatedTypeSpecifierSyntax``, or `nil` if the cast fails. + public func `as`(_ syntaxType: NonisolatedTypeSpecifierSyntax.Type) -> NonisolatedTypeSpecifierSyntax? { + return NonisolatedTypeSpecifierSyntax.init(self) + } + + /// Force-casts the current syntax node to ``NonisolatedTypeSpecifierSyntax``. + /// + /// - Returns: An instance of ``NonisolatedTypeSpecifierSyntax``. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + public func cast(_ syntaxType: NonisolatedTypeSpecifierSyntax.Type) -> NonisolatedTypeSpecifierSyntax { + return self.as(NonisolatedTypeSpecifierSyntax.self)! + } } public let _syntaxNode: Syntax diff --git a/Sources/SwiftSyntax/generated/SyntaxEnum.swift b/Sources/SwiftSyntax/generated/SyntaxEnum.swift index dacab406c29..283c1d82d03 100644 --- a/Sources/SwiftSyntax/generated/SyntaxEnum.swift +++ b/Sources/SwiftSyntax/generated/SyntaxEnum.swift @@ -216,6 +216,8 @@ public enum SyntaxEnum: Sendable { case multipleTrailingClosureElement(MultipleTrailingClosureElementSyntax) case namedOpaqueReturnType(NamedOpaqueReturnTypeSyntax) case nilLiteralExpr(NilLiteralExprSyntax) + case nonisolatedSpecifierArgument(NonisolatedSpecifierArgumentSyntax) + case nonisolatedTypeSpecifier(NonisolatedTypeSpecifierSyntax) case objCSelectorPieceList(ObjCSelectorPieceListSyntax) case objCSelectorPiece(ObjCSelectorPieceSyntax) case operatorDecl(OperatorDeclSyntax) @@ -699,6 +701,10 @@ extension Syntax { return .namedOpaqueReturnType(NamedOpaqueReturnTypeSyntax(self)!) case .nilLiteralExpr: return .nilLiteralExpr(NilLiteralExprSyntax(self)!) + case .nonisolatedSpecifierArgument: + return .nonisolatedSpecifierArgument(NonisolatedSpecifierArgumentSyntax(self)!) + case .nonisolatedTypeSpecifier: + return .nonisolatedTypeSpecifier(NonisolatedTypeSpecifierSyntax(self)!) case .objCSelectorPieceList: return .objCSelectorPieceList(ObjCSelectorPieceListSyntax(self)!) case .objCSelectorPiece: diff --git a/Sources/SwiftSyntax/generated/SyntaxKind.swift b/Sources/SwiftSyntax/generated/SyntaxKind.swift index f1476b00ef4..62883dd7ac3 100644 --- a/Sources/SwiftSyntax/generated/SyntaxKind.swift +++ b/Sources/SwiftSyntax/generated/SyntaxKind.swift @@ -216,6 +216,8 @@ public enum SyntaxKind: Sendable { case multipleTrailingClosureElement case namedOpaqueReturnType case nilLiteralExpr + case nonisolatedSpecifierArgument + case nonisolatedTypeSpecifier case objCSelectorPieceList case objCSelectorPiece case operatorDecl @@ -824,6 +826,10 @@ public enum SyntaxKind: Sendable { return NamedOpaqueReturnTypeSyntax.self case .nilLiteralExpr: return NilLiteralExprSyntax.self + case .nonisolatedSpecifierArgument: + return NonisolatedSpecifierArgumentSyntax.self + case .nonisolatedTypeSpecifier: + return NonisolatedTypeSpecifierSyntax.self case .objCSelectorPieceList: return ObjCSelectorPieceListSyntax.self case .objCSelectorPiece: diff --git a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift index fe361ee516f..77eb14701ba 100644 --- a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift +++ b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift @@ -1427,6 +1427,20 @@ open class SyntaxRewriter { return ExprSyntax(NilLiteralExprSyntax(unsafeCasting: visitChildren(node._syntaxNode))) } + /// Visit a ``NonisolatedSpecifierArgumentSyntax``. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + open func visit(_ node: NonisolatedSpecifierArgumentSyntax) -> NonisolatedSpecifierArgumentSyntax { + return NonisolatedSpecifierArgumentSyntax(unsafeCasting: visitChildren(node._syntaxNode)) + } + + /// Visit a ``NonisolatedTypeSpecifierSyntax``. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + open func visit(_ node: NonisolatedTypeSpecifierSyntax) -> NonisolatedTypeSpecifierSyntax { + return NonisolatedTypeSpecifierSyntax(unsafeCasting: visitChildren(node._syntaxNode)) + } + /// Visit a ``ObjCSelectorPieceListSyntax``. /// - Parameter node: the node that is being visited /// - Returns: the rewritten node @@ -3094,6 +3108,16 @@ open class SyntaxRewriter { Syntax(visit(NilLiteralExprSyntax(unsafeCasting: node))) } + @inline(never) + private func visitNonisolatedSpecifierArgumentSyntaxImpl(_ node: Syntax) -> Syntax { + Syntax(visit(NonisolatedSpecifierArgumentSyntax(unsafeCasting: node))) + } + + @inline(never) + private func visitNonisolatedTypeSpecifierSyntaxImpl(_ node: Syntax) -> Syntax { + Syntax(visit(NonisolatedTypeSpecifierSyntax(unsafeCasting: node))) + } + @inline(never) private func visitObjCSelectorPieceListSyntaxImpl(_ node: Syntax) -> Syntax { Syntax(visit(ObjCSelectorPieceListSyntax(unsafeCasting: node))) @@ -3988,6 +4012,10 @@ open class SyntaxRewriter { return self.visitNamedOpaqueReturnTypeSyntaxImpl(_:) case .nilLiteralExpr: return self.visitNilLiteralExprSyntaxImpl(_:) + case .nonisolatedSpecifierArgument: + return self.visitNonisolatedSpecifierArgumentSyntaxImpl(_:) + case .nonisolatedTypeSpecifier: + return self.visitNonisolatedTypeSpecifierSyntaxImpl(_:) case .objCSelectorPieceList: return self.visitObjCSelectorPieceListSyntaxImpl(_:) case .objCSelectorPiece: @@ -4570,6 +4598,10 @@ open class SyntaxRewriter { return visitNamedOpaqueReturnTypeSyntaxImpl(node) case .nilLiteralExpr: return visitNilLiteralExprSyntaxImpl(node) + case .nonisolatedSpecifierArgument: + return visitNonisolatedSpecifierArgumentSyntaxImpl(node) + case .nonisolatedTypeSpecifier: + return visitNonisolatedTypeSpecifierSyntaxImpl(node) case .objCSelectorPieceList: return visitObjCSelectorPieceListSyntaxImpl(node) case .objCSelectorPiece: diff --git a/Sources/SwiftSyntax/generated/SyntaxTraits.swift b/Sources/SwiftSyntax/generated/SyntaxTraits.swift index bf4e7438523..368b529b45b 100644 --- a/Sources/SwiftSyntax/generated/SyntaxTraits.swift +++ b/Sources/SwiftSyntax/generated/SyntaxTraits.swift @@ -802,6 +802,8 @@ extension MissingSyntax: MissingNodeSyntax {} extension MissingTypeSyntax: MissingNodeSyntax {} +extension NonisolatedSpecifierArgumentSyntax: ParenthesizedSyntax {} + extension OperatorDeclSyntax: NamedDeclSyntax {} extension PatternBindingSyntax: WithTrailingCommaSyntax {} diff --git a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift index f6c0bbd35f2..739a203874c 100644 --- a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift @@ -2315,6 +2315,30 @@ open class SyntaxVisitor { open func visitPost(_ node: NilLiteralExprSyntax) { } + /// Visiting ``NonisolatedSpecifierArgumentSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + open func visit(_ node: NonisolatedSpecifierArgumentSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting ``NonisolatedSpecifierArgumentSyntax`` and its descendants. + /// - node: the node we just finished visiting. + open func visitPost(_ node: NonisolatedSpecifierArgumentSyntax) { + } + + /// Visiting ``NonisolatedTypeSpecifierSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + open func visit(_ node: NonisolatedTypeSpecifierSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting ``NonisolatedTypeSpecifierSyntax`` and its descendants. + /// - node: the node we just finished visiting. + open func visitPost(_ node: NonisolatedTypeSpecifierSyntax) { + } + /// Visiting ``ObjCSelectorPieceListSyntax`` specifically. /// - Parameter node: the node we are visiting. /// - Returns: how should we continue visiting. @@ -5016,6 +5040,22 @@ open class SyntaxVisitor { visitPost(NilLiteralExprSyntax(unsafeCasting: node)) } + @inline(never) + private func visitNonisolatedSpecifierArgumentSyntaxImpl(_ node: Syntax) { + if visit(NonisolatedSpecifierArgumentSyntax(unsafeCasting: node)) == .visitChildren { + visitChildren(node) + } + visitPost(NonisolatedSpecifierArgumentSyntax(unsafeCasting: node)) + } + + @inline(never) + private func visitNonisolatedTypeSpecifierSyntaxImpl(_ node: Syntax) { + if visit(NonisolatedTypeSpecifierSyntax(unsafeCasting: node)) == .visitChildren { + visitChildren(node) + } + visitPost(NonisolatedTypeSpecifierSyntax(unsafeCasting: node)) + } + @inline(never) private func visitObjCSelectorPieceListSyntaxImpl(_ node: Syntax) { if visit(ObjCSelectorPieceListSyntax(unsafeCasting: node)) == .visitChildren { @@ -6204,6 +6244,10 @@ open class SyntaxVisitor { return self.visitNamedOpaqueReturnTypeSyntaxImpl(_:) case .nilLiteralExpr: return self.visitNilLiteralExprSyntaxImpl(_:) + case .nonisolatedSpecifierArgument: + return self.visitNonisolatedSpecifierArgumentSyntaxImpl(_:) + case .nonisolatedTypeSpecifier: + return self.visitNonisolatedTypeSpecifierSyntaxImpl(_:) case .objCSelectorPieceList: return self.visitObjCSelectorPieceListSyntaxImpl(_:) case .objCSelectorPiece: @@ -6786,6 +6830,10 @@ open class SyntaxVisitor { self.visitNamedOpaqueReturnTypeSyntaxImpl(node) case .nilLiteralExpr: self.visitNilLiteralExprSyntaxImpl(node) + case .nonisolatedSpecifierArgument: + self.visitNonisolatedSpecifierArgumentSyntaxImpl(node) + case .nonisolatedTypeSpecifier: + self.visitNonisolatedTypeSpecifierSyntaxImpl(node) case .objCSelectorPieceList: self.visitObjCSelectorPieceListSyntaxImpl(node) case .objCSelectorPiece: diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesJKLMN.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesJKLMN.swift index 5f8cbf238d2..8e6766d2c4f 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesJKLMN.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesJKLMN.swift @@ -2957,3 +2957,155 @@ public struct RawNilLiteralExprSyntax: RawExprSyntaxNodeProtocol { layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) } } + +@_spi(RawSyntax) +public struct RawNonisolatedSpecifierArgumentSyntax: RawSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .nonisolatedSpecifierArgument + } + + public var raw: RawSyntax + + init(raw: RawSyntax) { + precondition(Self.isKindOf(raw)) + self.raw = raw + } + + private init(unchecked raw: RawSyntax) { + self.raw = raw + } + + public init?(_ other: some RawSyntaxNodeProtocol) { + guard Self.isKindOf(other.raw) else { + return nil + } + self.init(unchecked: other.raw) + } + + public init( + _ unexpectedBeforeLeftParen: RawUnexpectedNodesSyntax? = nil, + leftParen: RawTokenSyntax, + _ unexpectedBetweenLeftParenAndNonsendingKeyword: RawUnexpectedNodesSyntax? = nil, + nonsendingKeyword: RawTokenSyntax, + _ unexpectedBetweenNonsendingKeywordAndRightParen: RawUnexpectedNodesSyntax? = nil, + rightParen: RawTokenSyntax, + _ unexpectedAfterRightParen: RawUnexpectedNodesSyntax? = nil, + arena: __shared RawSyntaxArena + ) { + let raw = RawSyntax.makeLayout( + kind: .nonisolatedSpecifierArgument, uninitializedCount: 7, arena: arena) { layout in + layout.initialize(repeating: nil) + layout[0] = unexpectedBeforeLeftParen?.raw + layout[1] = leftParen.raw + layout[2] = unexpectedBetweenLeftParenAndNonsendingKeyword?.raw + layout[3] = nonsendingKeyword.raw + layout[4] = unexpectedBetweenNonsendingKeywordAndRightParen?.raw + layout[5] = rightParen.raw + layout[6] = unexpectedAfterRightParen?.raw + } + self.init(unchecked: raw) + } + + public var unexpectedBeforeLeftParen: RawUnexpectedNodesSyntax? { + layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var leftParen: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedBetweenLeftParenAndNonsendingKeyword: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var nonsendingKeyword: RawTokenSyntax { + layoutView.children[3].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedBetweenNonsendingKeywordAndRightParen: RawUnexpectedNodesSyntax? { + layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var rightParen: RawTokenSyntax { + layoutView.children[5].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterRightParen: RawUnexpectedNodesSyntax? { + layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + } +} + +@_spi(RawSyntax) +public struct RawNonisolatedTypeSpecifierSyntax: RawSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .nonisolatedTypeSpecifier + } + + public var raw: RawSyntax + + init(raw: RawSyntax) { + precondition(Self.isKindOf(raw)) + self.raw = raw + } + + private init(unchecked raw: RawSyntax) { + self.raw = raw + } + + public init?(_ other: some RawSyntaxNodeProtocol) { + guard Self.isKindOf(other.raw) else { + return nil + } + self.init(unchecked: other.raw) + } + + public init( + _ unexpectedBeforeNonisolatedKeyword: RawUnexpectedNodesSyntax? = nil, + nonisolatedKeyword: RawTokenSyntax, + _ unexpectedBetweenNonisolatedKeywordAndArgument: RawUnexpectedNodesSyntax? = nil, + argument: RawNonisolatedSpecifierArgumentSyntax?, + _ unexpectedAfterArgument: RawUnexpectedNodesSyntax? = nil, + arena: __shared RawSyntaxArena + ) { + let raw = RawSyntax.makeLayout( + kind: .nonisolatedTypeSpecifier, uninitializedCount: 5, arena: arena) { layout in + layout.initialize(repeating: nil) + layout[0] = unexpectedBeforeNonisolatedKeyword?.raw + layout[1] = nonisolatedKeyword.raw + layout[2] = unexpectedBetweenNonisolatedKeywordAndArgument?.raw + layout[3] = argument?.raw + layout[4] = unexpectedAfterArgument?.raw + } + self.init(unchecked: raw) + } + + public var unexpectedBeforeNonisolatedKeyword: RawUnexpectedNodesSyntax? { + layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var nonisolatedKeyword: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedBetweenNonisolatedKeywordAndArgument: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var argument: RawNonisolatedSpecifierArgumentSyntax? { + layoutView.children[3].map(RawNonisolatedSpecifierArgumentSyntax.init(raw:)) + } + + public var unexpectedAfterArgument: RawUnexpectedNodesSyntax? { + layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) + } +} diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift index 9dafdb8a7bf..e4b5a2b69a0 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift @@ -1416,9 +1416,10 @@ public struct RawTypeSpecifierListSyntax: RawSyntaxNodeProtocol { /// - Note: Requires experimental feature `nonescapableTypes`. @_spi(ExperimentalLanguageFeatures) case lifetimeTypeSpecifier(RawLifetimeTypeSpecifierSyntax) + case nonisolatedTypeSpecifier(RawNonisolatedTypeSpecifierSyntax) public static func isKindOf(_ raw: RawSyntax) -> Bool { - RawSimpleTypeSpecifierSyntax.isKindOf(raw) || RawLifetimeTypeSpecifierSyntax.isKindOf(raw) + RawSimpleTypeSpecifierSyntax.isKindOf(raw) || RawLifetimeTypeSpecifierSyntax.isKindOf(raw) || RawNonisolatedTypeSpecifierSyntax.isKindOf(raw) } public var raw: RawSyntax { @@ -1427,6 +1428,8 @@ public struct RawTypeSpecifierListSyntax: RawSyntaxNodeProtocol { return node.raw case .lifetimeTypeSpecifier(let node): return node.raw + case .nonisolatedTypeSpecifier(let node): + return node.raw } } @@ -1435,6 +1438,8 @@ public struct RawTypeSpecifierListSyntax: RawSyntaxNodeProtocol { self = .simpleTypeSpecifier(node) } else if let node = node.as(RawLifetimeTypeSpecifierSyntax.self) { self = .lifetimeTypeSpecifier(node) + } else if let node = node.as(RawNonisolatedTypeSpecifierSyntax.self) { + self = .nonisolatedTypeSpecifier(node) } else { return nil } diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index bfbbbbe2053..0ca5359f6e7 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -2150,6 +2150,24 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.keyword("nil")])) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) } + func validateNonisolatedSpecifierArgumentSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { + assert(layout.count == 7) + assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.leftParen)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self, tokenChoices: [.keyword("nonsending")])) + assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.rightParen)])) + assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) + } + func validateNonisolatedTypeSpecifierSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { + assert(layout.count == 5) + assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.keyword("nonisolated")])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 3, verify(layout[3], as: RawNonisolatedSpecifierArgumentSyntax?.self)) + assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) + } func validateObjCSelectorPieceListSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { for (index, element) in layout.enumerated() { assertNoError(kind, index, verify(element, as: RawObjCSelectorPieceSyntax.self)) @@ -2561,7 +2579,6 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { .keyword("__shared"), .keyword("__owned"), .keyword("isolated"), - .keyword("nonisolated"), .keyword("_const"), .keyword("borrowing"), .keyword("consuming"), @@ -2957,7 +2974,8 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { for (index, element) in layout.enumerated() { assertAnyHasNoError(kind, index, [ verify(element, as: RawSimpleTypeSpecifierSyntax.self), - verify(element, as: RawLifetimeTypeSpecifierSyntax.self)]) + verify(element, as: RawLifetimeTypeSpecifierSyntax.self), + verify(element, as: RawNonisolatedTypeSpecifierSyntax.self)]) } } func validateUnexpectedNodesSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { @@ -3488,6 +3506,10 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { validateNamedOpaqueReturnTypeSyntax(kind: kind, layout: layout) case .nilLiteralExpr: validateNilLiteralExprSyntax(kind: kind, layout: layout) + case .nonisolatedSpecifierArgument: + validateNonisolatedSpecifierArgumentSyntax(kind: kind, layout: layout) + case .nonisolatedTypeSpecifier: + validateNonisolatedTypeSpecifierSyntax(kind: kind, layout: layout) case .objCSelectorPieceList: validateObjCSelectorPieceListSyntax(kind: kind, layout: layout) case .objCSelectorPiece: diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesJKLMN.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesJKLMN.swift index 686cb752a0b..fe4e496d5ab 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesJKLMN.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesJKLMN.swift @@ -5507,3 +5507,283 @@ public struct NilLiteralExprSyntax: ExprSyntaxProtocol, SyntaxHashable, _LeafExp public static let structure: SyntaxNodeStructure = .layout([\Self.unexpectedBeforeNilKeyword, \Self.nilKeyword, \Self.unexpectedAfterNilKeyword]) } + +// MARK: - NonisolatedSpecifierArgumentSyntax + +/// A single argument that can be added to a nonisolated specifier: 'nonsending'. +/// +/// ### Example +/// `data` in `func foo(data: nonisolated(nonsending) () async -> Void) -> X` +/// +/// ### Children +/// +/// - `leftParen`: `(` +/// - `nonsendingKeyword`: `nonsending` +/// - `rightParen`: `)` +/// +/// ### Contained in +/// +/// - ``NonisolatedTypeSpecifierSyntax``.``NonisolatedTypeSpecifierSyntax/argument`` +public struct NonisolatedSpecifierArgumentSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNodeProtocol { + public let _syntaxNode: Syntax + + public init?(_ node: __shared some SyntaxProtocol) { + guard node.raw.kind == .nonisolatedSpecifierArgument else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + @_transparent + init(unsafeCasting node: Syntax) { + self._syntaxNode = node + } + + /// - Parameters: + /// - leadingTrivia: Trivia to be prepended to the leading trivia of the node’s first token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + /// - trailingTrivia: Trivia to be appended to the trailing trivia of the node’s last token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeLeftParen: UnexpectedNodesSyntax? = nil, + leftParen: TokenSyntax = .leftParenToken(), + _ unexpectedBetweenLeftParenAndNonsendingKeyword: UnexpectedNodesSyntax? = nil, + nonsendingKeyword: TokenSyntax = .keyword(.nonsending), + _ unexpectedBetweenNonsendingKeywordAndRightParen: UnexpectedNodesSyntax? = nil, + rightParen: TokenSyntax = .rightParenToken(), + _ unexpectedAfterRightParen: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { + // Extend the lifetime of all parameters so their arenas don't get destroyed + // before they can be added as children of the new arena. + self = withExtendedLifetime((RawSyntaxArena(), ( + unexpectedBeforeLeftParen, + leftParen, + unexpectedBetweenLeftParenAndNonsendingKeyword, + nonsendingKeyword, + unexpectedBetweenNonsendingKeywordAndRightParen, + rightParen, + unexpectedAfterRightParen + ))) { (arena, _) in + let layout: [RawSyntax?] = [ + unexpectedBeforeLeftParen?.raw, + leftParen.raw, + unexpectedBetweenLeftParenAndNonsendingKeyword?.raw, + nonsendingKeyword.raw, + unexpectedBetweenNonsendingKeywordAndRightParen?.raw, + rightParen.raw, + unexpectedAfterRightParen?.raw + ] + let raw = RawSyntax.makeLayout( + kind: SyntaxKind.nonisolatedSpecifierArgument, + from: layout, + arena: arena, + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia + ) + return Syntax.forRoot(raw, rawNodeArena: arena).cast(Self.self) + } + } + + public var unexpectedBeforeLeftParen: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 0)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 0, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + /// ### Tokens + /// + /// For syntax trees generated by the parser, this is guaranteed to be `(`. + public var leftParen: TokenSyntax { + get { + return Syntax(self).child(at: 1)!.cast(TokenSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 1, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + public var unexpectedBetweenLeftParenAndNonsendingKeyword: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 2)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 2, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + /// ### Tokens + /// + /// For syntax trees generated by the parser, this is guaranteed to be `nonsending`. + public var nonsendingKeyword: TokenSyntax { + get { + return Syntax(self).child(at: 3)!.cast(TokenSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 3, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + public var unexpectedBetweenNonsendingKeywordAndRightParen: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 4)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 4, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + /// ### Tokens + /// + /// For syntax trees generated by the parser, this is guaranteed to be `)`. + public var rightParen: TokenSyntax { + get { + return Syntax(self).child(at: 5)!.cast(TokenSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 5, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + public var unexpectedAfterRightParen: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 6)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 6, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedSpecifierArgumentSyntax.self) + } + } + + public static let structure: SyntaxNodeStructure = .layout([ + \Self.unexpectedBeforeLeftParen, + \Self.leftParen, + \Self.unexpectedBetweenLeftParenAndNonsendingKeyword, + \Self.nonsendingKeyword, + \Self.unexpectedBetweenNonsendingKeywordAndRightParen, + \Self.rightParen, + \Self.unexpectedAfterRightParen + ]) +} + +// MARK: - NonisolatedTypeSpecifierSyntax + +/// ### Children +/// +/// - `nonisolatedKeyword`: `nonisolated` +/// - `argument`: ``NonisolatedSpecifierArgumentSyntax``? +/// +/// ### Contained in +/// +/// - ``TypeSpecifierListSyntax`` +public struct NonisolatedTypeSpecifierSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNodeProtocol { + public let _syntaxNode: Syntax + + public init?(_ node: __shared some SyntaxProtocol) { + guard node.raw.kind == .nonisolatedTypeSpecifier else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + @_transparent + init(unsafeCasting node: Syntax) { + self._syntaxNode = node + } + + /// - Parameters: + /// - leadingTrivia: Trivia to be prepended to the leading trivia of the node’s first token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + /// - trailingTrivia: Trivia to be appended to the trailing trivia of the node’s last token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeNonisolatedKeyword: UnexpectedNodesSyntax? = nil, + nonisolatedKeyword: TokenSyntax = .keyword(.nonisolated), + _ unexpectedBetweenNonisolatedKeywordAndArgument: UnexpectedNodesSyntax? = nil, + argument: NonisolatedSpecifierArgumentSyntax? = nil, + _ unexpectedAfterArgument: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { + // Extend the lifetime of all parameters so their arenas don't get destroyed + // before they can be added as children of the new arena. + self = withExtendedLifetime((RawSyntaxArena(), ( + unexpectedBeforeNonisolatedKeyword, + nonisolatedKeyword, + unexpectedBetweenNonisolatedKeywordAndArgument, + argument, + unexpectedAfterArgument + ))) { (arena, _) in + let layout: [RawSyntax?] = [ + unexpectedBeforeNonisolatedKeyword?.raw, + nonisolatedKeyword.raw, + unexpectedBetweenNonisolatedKeywordAndArgument?.raw, + argument?.raw, + unexpectedAfterArgument?.raw + ] + let raw = RawSyntax.makeLayout( + kind: SyntaxKind.nonisolatedTypeSpecifier, + from: layout, + arena: arena, + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia + ) + return Syntax.forRoot(raw, rawNodeArena: arena).cast(Self.self) + } + } + + public var unexpectedBeforeNonisolatedKeyword: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 0)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 0, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedTypeSpecifierSyntax.self) + } + } + + /// ### Tokens + /// + /// For syntax trees generated by the parser, this is guaranteed to be `nonisolated`. + public var nonisolatedKeyword: TokenSyntax { + get { + return Syntax(self).child(at: 1)!.cast(TokenSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 1, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedTypeSpecifierSyntax.self) + } + } + + public var unexpectedBetweenNonisolatedKeywordAndArgument: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 2)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 2, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedTypeSpecifierSyntax.self) + } + } + + public var argument: NonisolatedSpecifierArgumentSyntax? { + get { + return Syntax(self).child(at: 3)?.cast(NonisolatedSpecifierArgumentSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 3, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedTypeSpecifierSyntax.self) + } + } + + public var unexpectedAfterArgument: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 4)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 4, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(NonisolatedTypeSpecifierSyntax.self) + } + } + + public static let structure: SyntaxNodeStructure = .layout([ + \Self.unexpectedBeforeNonisolatedKeyword, + \Self.nonisolatedKeyword, + \Self.unexpectedBetweenNonisolatedKeywordAndArgument, + \Self.argument, + \Self.unexpectedAfterArgument + ]) +} diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift index 0be78ad525d..2431b585fc8 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift @@ -1267,7 +1267,7 @@ public struct SimpleStringLiteralExprSyntax: ExprSyntaxProtocol, SyntaxHashable, /// /// ### Children /// -/// - `specifier`: (`inout` | `__shared` | `__owned` | `isolated` | `nonisolated` | `_const` | `borrowing` | `consuming` | `sending`) +/// - `specifier`: (`inout` | `__shared` | `__owned` | `isolated` | `_const` | `borrowing` | `consuming` | `sending`) /// /// ### Contained in /// @@ -1331,7 +1331,6 @@ public struct SimpleTypeSpecifierSyntax: SyntaxProtocol, SyntaxHashable, _LeafSy /// - `__shared` /// - `__owned` /// - `isolated` - /// - `nonisolated` /// - `_const` /// - `borrowing` /// - `consuming` diff --git a/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift b/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift index c6c34003dfa..f1c1a598825 100644 --- a/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift +++ b/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift @@ -697,6 +697,10 @@ public struct TypeSpecifierListBuilder: ListBuilder { public static func buildExpression(_ expression: LifetimeTypeSpecifierSyntax) -> Component { buildExpression(.init(expression)) } + + public static func buildExpression(_ expression: NonisolatedTypeSpecifierSyntax) -> Component { + buildExpression(.init(expression)) + } } extension TypeSpecifierListSyntax { diff --git a/Tests/SwiftDiagnosticsTest/DiagnosticFormatterTests.swift b/Tests/SwiftDiagnosticsTest/DiagnosticFormatterTests.swift new file mode 100644 index 00000000000..2980b046504 --- /dev/null +++ b/Tests/SwiftDiagnosticsTest/DiagnosticFormatterTests.swift @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftDiagnostics +import XCTest + +final class DiagnosticFormatterTests: XCTestCase { + func testFormattedMessage() { + let message = SimpleDiagnosticMessage( + message: "something went wrong", + diagnosticID: MessageID(domain: "swift-syntax", id: "testing"), + severity: .error, + category: DiagnosticCategory( + name: "Testing", + documentationURL: "http://example.com" + ) + ) + + let formattedText = DiagnosticsFormatter().formattedMessage(message) + XCTAssertEqual(formattedText, "error: something went wrong [#Testing]") + } +} diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index 261edaf59e6..7ec097ec5bd 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -261,8 +261,8 @@ final class DeclarationTests: ParserTestCase { """, diagnostics: [ DiagnosticSpec( - message: "expected 'unsafe' in modifier", - fixIts: ["replace 'safe' with 'unsafe'"] + message: "expected identifier in modifier", + fixIts: ["replace 'safe' with identifier"] ) ], fixedSource: """ @@ -271,7 +271,36 @@ final class DeclarationTests: ParserTestCase { struct A { nonisolated(unsafe) let b = 0 nonisolated(unsafe) var c: Int { 0 } - nonisolated(unsafe) let d = 0 + nonisolated(<#identifier#>) let d = 0 + } + """ + ) + } + + func testNonisolatedNonSendingParsing() { + assertParse( + """ + nonisolated(nonsending) let a = 0 + + struct A { + nonisolated(nonsending) let b = 0 + nonisolated(nonsending) var c: Int { 0 } + nonisolated(1️⃣sending) let d = 0 + } + """, + diagnostics: [ + DiagnosticSpec( + message: "expected identifier in modifier", + fixIts: ["replace 'sending' with identifier"] + ) + ], + fixedSource: """ + nonisolated(nonsending) let a = 0 + + struct A { + nonisolated(nonsending) let b = 0 + nonisolated(nonsending) var c: Int { 0 } + nonisolated(<#identifier#>) let d = 0 } """ ) diff --git a/Tests/SwiftParserTest/TypeTests.swift b/Tests/SwiftParserTest/TypeTests.swift index 588c1be8beb..6e49d5fa75d 100644 --- a/Tests/SwiftParserTest/TypeTests.swift +++ b/Tests/SwiftParserTest/TypeTests.swift @@ -485,6 +485,20 @@ final class TypeTests: ParserTestCase { experimentalFeatures: [.nonescapableTypes] ) + assertParse( + "func foo() -> dependsOn1️⃣ @Sendable (Int, isolated (any Actor)?) async throws -> Void", + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "expected '(', parameter reference, and ')' in lifetime specifier", + fixIts: ["insert '(', parameter reference, and ')'"] + ) + ], + fixedSource: + "func foo() -> dependsOn(<#identifier#>) @Sendable (Int, isolated (any Actor)?) async throws -> Void", + experimentalFeatures: [.nonescapableTypes] + ) + assertParse( "func foo() -> dependsOn(1️⃣*) X", diagnostics: [ @@ -537,6 +551,189 @@ final class TypeTests: ParserTestCase { experimentalFeatures: [.nonescapableTypes] ) } + + func testNonisolatedSpecifier() { + assertParse( + """ + let x = nonisolated + print("hello") + """, + substructure: DeclReferenceExprSyntax( + baseName: .identifier("nonisolated") + ) + ) + + assertParse( + "let _: nonisolated(nonsending) () async -> Void = {}", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + assertParse( + "let _: [nonisolated(nonsending) () async -> Void]", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + + assertParse( + "let _ = [String: (nonisolated(nonsending) () async -> Void)?].self", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + + assertParse( + "let _ = Array Void>()", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + assertParse( + "func foo(test: nonisolated(nonsending) () async -> Void)", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + assertParse( + "func foo(test: nonisolated(nonsending) @escaping () async -> Void) {}", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + assertParse( + "test(S Void>(), type(of: concurrentTest))", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + assertParse( + "S Void>()", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + assertParse( + "let _ = S Void>()", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + + assertParse( + "struct S : nonisolated P {}", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated) + ) + ) + + assertParse( + "let _ = [nonisolated()]", + substructure: DeclReferenceExprSyntax( + baseName: .identifier("nonisolated") + ) + ) + + assertParse( + "let _ = [nonisolated(nonsending) () async -> Void]()", + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated), + argument: NonisolatedSpecifierArgumentSyntax(nonsendingKeyword: .keyword(.nonsending)) + ) + ) + + assertParse( + "_ = S()", + substructure: GenericArgumentSyntax.Argument( + IdentifierTypeSyntax(name: .identifier("nonisolated")) + ) + ) + + assertParse( + """ + let x: nonisolated + (hello) + """, + substructure: IdentifierTypeSyntax(name: .identifier("nonisolated")) + ) + + assertParse( + """ + struct S: nonisolated + P { + } + """, + substructure: NonisolatedTypeSpecifierSyntax( + nonisolatedKeyword: .keyword(.nonisolated) + ) + ) + + assertParse( + """ + let x: nonisolated + (Int) async -> Void = {} + """, + substructure: IdentifierTypeSyntax(name: .identifier("nonisolated")) + ) + + assertParse( + "Foo Void>()", + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "expected '(nonsending)' in 'nonisolated' specifier", + fixIts: ["insert '(nonsending)'"] + ) + ], + fixedSource: "Foo Void>()" + ) + + assertParse( + "func foo(test: nonisolated1️⃣ () async -> Void)", + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "expected '(nonsending)' in 'nonisolated' specifier", + fixIts: ["insert '(nonsending)'"] + ) + ], + fixedSource: "func foo(test: nonisolated(nonsending) () async -> Void)" + ) + + assertParse( + "func foo(test: nonisolated(1️⃣) () async -> Void)", + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "expected 'nonsending' in 'nonisolated' specifier", + fixIts: ["insert 'nonsending'"] + ) + ], + fixedSource: "func foo(test: nonisolated(nonsending) () async -> Void)" + ) + + assertParse( + "func foo(test: nonisolated(1️⃣hello) () async -> Void)", + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "expected 'nonsending' in 'nonisolated' specifier", + fixIts: ["insert 'nonsending'"] + ), + DiagnosticSpec(message: "unexpected code 'hello' in 'nonisolated' specifier"), + ], + fixedSource: "func foo(test: nonisolated(nonsendinghello) () async -> Void)" + ) + } } final class InlineArrayTypeTests: ParserTestCase {