Skip to content

Commit 59ef3f6

Browse files
committed
Make the Diagnose module build in Swift 6 mode
This was mostly about slapping `@MainActor` on a bunch of declarations since `diagnose` doesn’t leverage concurrency at the moment.
1 parent 2f14afb commit 59ef3f6

15 files changed

+93
-15
lines changed

Sources/Diagnose/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_library(Diagnose STATIC
2+
CommandConfiguration+Sendable.swift
23
CommandLineArgumentsReducer.swift
34
DiagnoseCommand.swift
45
MergeSwiftFiles.swift
@@ -11,9 +12,10 @@ add_library(Diagnose STATIC
1112
ReproducerBundle.swift
1213
RequestInfo.swift
1314
SourceKitD+RunWithYaml.swift
15+
SourcekitdRequestCommand.swift
1416
SourceKitDRequestExecutor.swift
1517
SourceReducer.swift
16-
SourcekitdRequestCommand.swift
18+
StderrStreamConcurrencySafe.swift
1719
SwiftFrontendCrashScraper.swift
1820
Toolchain+SwiftFrontend.swift)
1921

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
15+
// If `CommandConfiguration` is not sendable, commands can't have static `configuration` properties.
16+
// Needed until we update Swift CI to swift-argument-parser 1.3.1, which has this conformance (rdar://128042447).
17+
extension CommandConfiguration: @unchecked @retroactive Sendable {}

Sources/Diagnose/CommandLineArgumentsReducer.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import LSPLogging
1616
// MARK: - Entry point
1717

1818
extension RequestInfo {
19+
@MainActor
1920
func reduceCommandLineArguments(
2021
using executor: SourceKitRequestExecutor,
2122
progressUpdate: (_ progress: Double, _ message: String) -> Void
@@ -49,6 +50,7 @@ fileprivate class CommandLineArgumentReducer {
4950
self.progressUpdate = progressUpdate
5051
}
5152

53+
@MainActor
5254
func run(initialRequestInfo: RequestInfo) async throws -> RequestInfo {
5355
var requestInfo = initialRequestInfo
5456
requestInfo = try await reduce(initialRequestInfo: requestInfo, simultaneousRemove: 10)
@@ -113,6 +115,7 @@ fileprivate class CommandLineArgumentReducer {
113115
return requestInfo
114116
}
115117

118+
@MainActor
116119
private func tryRemoving(
117120
_ argumentsToRemove: ClosedRange<Int>,
118121
from requestInfo: RequestInfo

Sources/Diagnose/DiagnoseCommand.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ import SKCore
1616

1717
import struct TSCBasic.AbsolutePath
1818
import class TSCBasic.Process
19-
import var TSCBasic.stderrStream
2019
import class TSCUtility.PercentProgressAnimation
2120

2221
/// When diagnosis is started, a progress bar displayed on the terminal that shows how far the diagnose command has
2322
/// progressed.
2423
/// Can't be a member of `DiagnoseCommand` because then `DiagnoseCommand` is no longer codable, which it needs to be
2524
/// to be a `AsyncParsableCommand`.
25+
@MainActor
2626
private var progressBar: PercentProgressAnimation? = nil
2727

2828
/// A component of the diagnostic bundle that's collected in independent stages.
@@ -35,7 +35,7 @@ fileprivate enum BundleComponent: String, CaseIterable, ExpressibleByArgument {
3535
}
3636

3737
public struct DiagnoseCommand: AsyncParsableCommand {
38-
public static var configuration: CommandConfiguration = CommandConfiguration(
38+
public static let configuration: CommandConfiguration = CommandConfiguration(
3939
commandName: "diagnose",
4040
abstract: "Creates a bundle containing information that help diagnose issues with sourcekit-lsp"
4141
)
@@ -72,6 +72,7 @@ public struct DiagnoseCommand: AsyncParsableCommand {
7272
}
7373
}
7474

75+
@MainActor
7576
var toolchain: Toolchain? {
7677
get async throws {
7778
if let toolchainOverride {
@@ -96,6 +97,7 @@ public struct DiagnoseCommand: AsyncParsableCommand {
9697

9798
public init() {}
9899

100+
@MainActor
99101
private func addSourcekitdCrashReproducer(toBundle bundlePath: URL) async throws {
100102
reportProgress(.reproducingSourcekitdCrash(progress: 0), message: "Trying to reduce recent sourcekitd crashes")
101103
for (name, requestInfo) in try requestInfos() {
@@ -121,6 +123,7 @@ public struct DiagnoseCommand: AsyncParsableCommand {
121123
}
122124
}
123125

126+
@MainActor
124127
private func addSwiftFrontendCrashReproducer(toBundle bundlePath: URL) async throws {
125128
reportProgress(
126129
.reproducingSwiftFrontendCrash(progress: 0),
@@ -182,14 +185,16 @@ public struct DiagnoseCommand: AsyncParsableCommand {
182185
}
183186

184187
/// Execute body and if it throws, log the error.
185-
private func orPrintError(_ body: () async throws -> Void) async {
188+
@MainActor
189+
private func orPrintError(_ body: @MainActor () async throws -> Void) async {
186190
do {
187191
try await body()
188192
} catch {
189193
print(error)
190194
}
191195
}
192196

197+
@MainActor
193198
private func addOsLog(toBundle bundlePath: URL) async throws {
194199
#if os(macOS)
195200
reportProgress(.collectingLogMessages(progress: 0), message: "Collecting log messages")
@@ -227,6 +232,7 @@ public struct DiagnoseCommand: AsyncParsableCommand {
227232
#endif
228233
}
229234

235+
@MainActor
230236
private func addCrashLogs(toBundle bundlePath: URL) throws {
231237
#if os(macOS)
232238
reportProgress(.collectingCrashReports, message: "Collecting crash reports")
@@ -252,6 +258,7 @@ public struct DiagnoseCommand: AsyncParsableCommand {
252258
#endif
253259
}
254260

261+
@MainActor
255262
private func addSwiftVersion(toBundle bundlePath: URL) async throws {
256263
let outputFileUrl = bundlePath.appendingPathComponent("swift-versions.txt")
257264
FileManager.default.createFile(atPath: outputFileUrl.path, contents: nil)
@@ -283,10 +290,12 @@ public struct DiagnoseCommand: AsyncParsableCommand {
283290
}
284291
}
285292

293+
@MainActor
286294
private func reportProgress(_ state: DiagnoseProgressState, message: String) {
287295
progressBar?.update(step: Int(state.progress * 100), total: 100, text: message)
288296
}
289297

298+
@MainActor
290299
public func run() async throws {
291300
print(
292301
"""
@@ -303,7 +312,10 @@ public struct DiagnoseCommand: AsyncParsableCommand {
303312
"""
304313
)
305314

306-
progressBar = PercentProgressAnimation(stream: stderrStream, header: "Diagnosing sourcekit-lsp issues")
315+
progressBar = PercentProgressAnimation(
316+
stream: stderrStreamConcurrencySafe,
317+
header: "Diagnosing sourcekit-lsp issues"
318+
)
307319

308320
let dateFormatter = ISO8601DateFormatter()
309321
dateFormatter.timeZone = NSTimeZone.local
@@ -342,6 +354,7 @@ public struct DiagnoseCommand: AsyncParsableCommand {
342354

343355
}
344356

357+
@MainActor
345358
private func reduce(
346359
requestInfo: RequestInfo,
347360
toolchain: Toolchain?,

Sources/Diagnose/MergeSwiftFiles.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ extension RequestInfo {
1717
/// Check if the issue reproduces when merging all `.swift` input files into a single file.
1818
///
1919
/// Returns `nil` if the issue didn't reproduce with all `.swift` files merged.
20+
@MainActor
2021
func mergeSwiftFiles(
2122
using executor: SourceKitRequestExecutor,
2223
progressUpdate: (_ progress: Double, _ message: String) -> Void

Sources/Diagnose/ReduceCommand.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import var TSCBasic.stderrStream
2020
import class TSCUtility.PercentProgressAnimation
2121

2222
public struct ReduceCommand: AsyncParsableCommand {
23-
public static var configuration: CommandConfiguration = CommandConfiguration(
23+
public static let configuration: CommandConfiguration = CommandConfiguration(
2424
commandName: "reduce",
2525
abstract: "Reduce a single sourcekitd crash",
2626
shouldDisplay: false
@@ -56,6 +56,7 @@ public struct ReduceCommand: AsyncParsableCommand {
5656
private var nsPredicate: NSPredicate? { nil }
5757
#endif
5858

59+
@MainActor
5960
var toolchain: Toolchain? {
6061
get async throws {
6162
if let toolchainOverride {
@@ -68,6 +69,7 @@ public struct ReduceCommand: AsyncParsableCommand {
6869

6970
public init() {}
7071

72+
@MainActor
7173
public func run() async throws {
7274
guard let sourcekitd = try await toolchain?.sourcekitd else {
7375
throw ReductionError("Unable to find sourcekitd.framework")

Sources/Diagnose/ReduceFrontendCommand.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import var TSCBasic.stderrStream
2020
import class TSCUtility.PercentProgressAnimation
2121

2222
public struct ReduceFrontendCommand: AsyncParsableCommand {
23-
public static var configuration: CommandConfiguration = CommandConfiguration(
23+
public static let configuration: CommandConfiguration = CommandConfiguration(
2424
commandName: "reduce-frontend",
2525
abstract: "Reduce a single swift-frontend crash",
2626
shouldDisplay: false
@@ -64,6 +64,7 @@ public struct ReduceFrontendCommand: AsyncParsableCommand {
6464
)
6565
var frontendArgs: [String]
6666

67+
@MainActor
6768
var toolchain: Toolchain? {
6869
get async throws {
6970
if let toolchainOverride {
@@ -76,6 +77,7 @@ public struct ReduceFrontendCommand: AsyncParsableCommand {
7677

7778
public init() {}
7879

80+
@MainActor
7981
public func run() async throws {
8082
guard let sourcekitd = try await toolchain?.sourcekitd else {
8183
throw ReductionError("Unable to find sourcekitd.framework")
@@ -84,7 +86,10 @@ public struct ReduceFrontendCommand: AsyncParsableCommand {
8486
throw ReductionError("Unable to find swift-frontend")
8587
}
8688

87-
let progressBar = PercentProgressAnimation(stream: stderrStream, header: "Reducing swift-frontend crash")
89+
let progressBar = PercentProgressAnimation(
90+
stream: stderrStream,
91+
header: "Reducing swift-frontend crash"
92+
)
8893

8994
let executor = OutOfProcessSourceKitRequestExecutor(
9095
sourcekitd: sourcekitd.asURL,

Sources/Diagnose/ReduceSourceKitDRequest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
extension RequestInfo {
1414
/// Reduce the input file of this request and the command line arguments.
15+
@MainActor
1516
func reduce(
1617
using executor: SourceKitRequestExecutor,
1718
progressUpdate: (_ progress: Double, _ message: String) -> Void

Sources/Diagnose/ReduceSwiftFrontend.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
@MainActor
1314
@_spi(Testing)
1415
public func reduceFrontendIssue(
1516
frontendArgs: [String],

Sources/Diagnose/RequestInfo.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import RegexBuilder
1515

1616
/// All the information necessary to replay a sourcektid request.
1717
@_spi(Testing)
18-
public struct RequestInfo {
18+
public struct RequestInfo: Sendable {
1919
/// The JSON request object. Contains the following dynamic placeholders:
2020
/// - `$OFFSET`: To be replaced by `offset` before running the request
2121
/// - `$FILE`: Will be replaced with a path to the file that contains the reduced source code.
@@ -51,7 +51,7 @@ public struct RequestInfo {
5151
}
5252

5353
/// A fake value that is used to indicate that we are reducing a `swift-frontend` issue instead of a sourcekitd issue.
54-
static var fakeRequestTemplateForFrontendIssues = """
54+
static let fakeRequestTemplateForFrontendIssues = """
5555
{
5656
key.request: sourcekit-lsp-fake-request-for-frontend-crash
5757
key.compilerargs: [

Sources/Diagnose/SourceKitDRequestExecutor.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import struct TSCBasic.ProcessResult
1919

2020
/// The different states in which a sourcekitd request can finish.
2121
@_spi(Testing)
22-
public enum SourceKitDRequestResult {
22+
public enum SourceKitDRequestResult: Sendable {
2323
/// The request succeeded.
2424
case success(response: String)
2525

@@ -46,11 +46,12 @@ fileprivate extension String {
4646
/// An executor that can run a sourcekitd request and indicate whether the request reprodes a specified issue.
4747
@_spi(Testing)
4848
public protocol SourceKitRequestExecutor {
49-
func runSourceKitD(request: RequestInfo) async throws -> SourceKitDRequestResult
50-
func runSwiftFrontend(request: RequestInfo) async throws -> SourceKitDRequestResult
49+
@MainActor func runSourceKitD(request: RequestInfo) async throws -> SourceKitDRequestResult
50+
@MainActor func runSwiftFrontend(request: RequestInfo) async throws -> SourceKitDRequestResult
5151
}
5252

5353
extension SourceKitRequestExecutor {
54+
@MainActor
5455
func run(request: RequestInfo) async throws -> SourceKitDRequestResult {
5556
if request.requestTemplate == RequestInfo.fakeRequestTemplateForFrontendIssues {
5657
return try await runSwiftFrontend(request: request)

Sources/Diagnose/SourceReducer.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import SwiftSyntax
2121

2222
extension RequestInfo {
2323
@_spi(Testing)
24+
@MainActor
2425
public func reduceInputFile(
2526
using executor: SourceKitRequestExecutor,
2627
progressUpdate: (_ progress: Double, _ message: String) -> Void
@@ -61,6 +62,7 @@ fileprivate enum ReductionStepResult {
6162
}
6263

6364
/// Reduces an input source file while continuing to reproduce the crash
65+
@MainActor
6466
fileprivate class SourceReducer {
6567
/// The executor that is used to run a sourcekitd request and check whether it
6668
/// still crashes.
@@ -84,6 +86,7 @@ fileprivate class SourceReducer {
8486
}
8587

8688
/// Reduce the file contents in `initialRequest` to a smaller file that still reproduces a crash.
89+
@MainActor
8790
func run(initialRequestInfo: RequestInfo) async throws -> RequestInfo {
8891
var requestInfo = initialRequestInfo
8992
self.initialImportCount = Parser.parse(source: requestInfo.fileContents).numberOfImports
@@ -242,6 +245,7 @@ fileprivate class SourceReducer {
242245
///
243246
/// If the request still crashes after applying the edits computed by `reduce`, return the reduced request info.
244247
/// Otherwise, return `nil`
248+
@MainActor
245249
private func runReductionStep(
246250
requestInfo: RequestInfo,
247251
reportProgress: Bool = true,
@@ -608,6 +612,7 @@ fileprivate class FirstImportFinder: SyntaxAnyVisitor {
608612
/// the file that imports the module. If `areFallbackArgs` is set, we have synthesized fallback arguments that only
609613
/// contain a target and SDK. This is useful when reducing a swift-frontend crash because sourcekitd requires driver
610614
/// arguments but the swift-frontend crash has frontend args.
615+
@MainActor
611616
fileprivate func getSwiftInterface(
612617
_ moduleName: String,
613618
executor: SourceKitRequestExecutor,
@@ -680,6 +685,7 @@ fileprivate func getSwiftInterface(
680685
return try JSONDecoder().decode(String.self, from: sanitizedData)
681686
}
682687

688+
@MainActor
683689
fileprivate func inlineFirstImport(
684690
in tree: SourceFileSyntax,
685691
executor: SourceKitRequestExecutor,

Sources/Diagnose/SourcekitdRequestCommand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import SourceKitD
1818
import struct TSCBasic.AbsolutePath
1919

2020
public struct SourceKitdRequestCommand: AsyncParsableCommand {
21-
public static var configuration = CommandConfiguration(
21+
public static let configuration = CommandConfiguration(
2222
commandName: "run-sourcekitd-request",
2323
abstract: "Run a sourcekitd request and print its result",
2424
shouldDisplay: false
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TSCLibc
14+
15+
import class TSCBasic.LocalFileOutputByteStream
16+
import class TSCBasic.ThreadSafeOutputByteStream
17+
18+
// A version of `stderrStream` from `TSCBasic` that is a `let` and can thus be used from Swift 6.
19+
let stderrStreamConcurrencySafe: ThreadSafeOutputByteStream = try! ThreadSafeOutputByteStream(
20+
LocalFileOutputByteStream(
21+
filePointer: TSCLibc.stderr,
22+
closeOnDeinit: false
23+
)
24+
)

0 commit comments

Comments
 (0)