diff --git a/Sources/Rules/TrailingCommas.swift b/Sources/Rules/TrailingCommas.swift index 2d5ed12e6..aff7358b9 100644 --- a/Sources/Rules/TrailingCommas.swift +++ b/Sources/Rules/TrailingCommas.swift @@ -77,8 +77,8 @@ public extension FormatRule { { trailingCommaSupported = true - // However, this is one bug in Swift 6.2 where trailing commas are unexpectedly - // not allowed in tuple types within generic type argument lists. + // However, this is a bug in Swift 6.2 where trailing commas are unexpectedly + // not allowed in tuple types within generic type argument lists. // https://github.com/swiftlang/swift-syntax/pull/3153 if formatter.options.swiftVersion == "6.2" { var startOfScope = startOfScope @@ -91,6 +91,15 @@ public extension FormatRule { startOfScope = outerScope } } + + // There is also a bug in Swift 6.2 where closure tuple return types don't support trailing commas. + if formatter.options.swiftVersion == "6.2", + let tokenBeforeStartOfScope = formatter.index(of: .nonSpaceOrCommentOrLinebreak, before: startOfScope), + formatter.tokens[tokenBeforeStartOfScope] == .operator("->", .infix), + formatter.isInClosureArguments(at: tokenBeforeStartOfScope) + { + trailingCommaSupported = false + } } // In Swift 6.1, trailing commas are only supported in tuple values, diff --git a/Tests/Rules/TrailingCommasTests.swift b/Tests/Rules/TrailingCommasTests.swift index b97ea70ff..61bf40fd9 100644 --- a/Tests/Rules/TrailingCommasTests.swift +++ b/Tests/Rules/TrailingCommasTests.swift @@ -2451,6 +2451,81 @@ class TrailingCommasTests: XCTestCase { testFormatting(for: input, output, rule: .trailingCommas, options: options, exclude: [.typeSugar, .propertyTypes]) } + func testTrailingCommasNotAddedToClosureTupleReturnType() { + // Trailing commas are unexpectedly not allowed here in Swift 6.2 + let input = """ + let closure = { () -> ( + foo: String, + bar: String + ) in + (foo: "foo", bar: "bar") + } + + func foo() -> ( + foo: String, + bar: String + ) { + (foo: "foo", bar: "bar") + } + """ + + let output = """ + let closure = { () -> ( + foo: String, + bar: String + ) in + (foo: "foo", bar: "bar") + } + + func foo() -> ( + foo: String, + bar: String, + ) { + (foo: "foo", bar: "bar") + } + """ + + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.2") + testFormatting(for: input, output, rule: .trailingCommas, options: options, exclude: [.typeSugar, .propertyTypes]) + } + + func testTrailingCommasAddedToClosureTupleReturnTypeSwift6_3() { + let input = """ + let closure = { () -> ( + foo: String, + bar: String + ) in + (foo: "foo", bar: "bar") + } + + func foo() -> ( + foo: String, + bar: String + ) { + (foo: "foo", bar: "bar") + } + """ + + let output = """ + let closure = { () -> ( + foo: String, + bar: String, + ) in + (foo: "foo", bar: "bar") + } + + func foo() -> ( + foo: String, + bar: String, + ) { + (foo: "foo", bar: "bar") + } + """ + + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.3") + testFormatting(for: input, output, rule: .trailingCommas, options: options, exclude: [.typeSugar, .propertyTypes]) + } + func testTrailingCommasAddedToTupleFunctionArgumentInSwift6_2() { let input = """ func updateBackgroundMusic(