Skip to content

Merge main into release/6.2 #3063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/automerge.yml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ public enum Keyword: CaseIterable {
case none
case nonisolated
case nonmutating
case nonsending
case objc
case obsoleted
case of
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 47 additions & 2 deletions CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -689,7 +735,6 @@ public let TYPE_NODES: [Node] = [
.keyword(.__shared),
.keyword(.__owned),
.keyword(.isolated),
.keyword(.nonisolated),
.keyword(._const),
.keyword(.borrowing),
.keyword(.consuming),
Expand All @@ -704,6 +749,6 @@ public let TYPE_NODES: [Node] = [
kind: .typeSpecifierList,
base: .syntaxCollection,
nameForDiagnostics: nil,
elementChoices: [.simpleTypeSpecifier, .lifetimeTypeSpecifier]
elementChoices: [.simpleTypeSpecifier, .lifetimeTypeSpecifier, .nonisolatedTypeSpecifier]
),
]
5 changes: 5 additions & 0 deletions Release Notes/602.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftDiagnostics/DiagnosticsFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.,
Expand Down
6 changes: 3 additions & 3 deletions Sources/SwiftParser/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -1036,7 +1036,7 @@ extension Parser.Lookahead {
}

if self.at(TokenSpec(.leftParen, allowAtStartOfLine: false))
&& self.withLookahead({ $0.atCustomAttributeArgument() })
&& self.withLookahead({ $0.atAttributeOrSpecifierArgument() })
{
self.skipSingle()
}
Expand Down
30 changes: 28 additions & 2 deletions Sources/SwiftParser/Expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 5 additions & 1 deletion Sources/SwiftParser/Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions Sources/SwiftParser/TokenPrecedence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ enum TokenPrecedence: Comparable {
.module,
.noasync,
.none,
.nonsending,
.obsoleted,
.of,
.Protocol,
Expand Down
Loading