Skip to content

Commit d065eb8

Browse files
committed
SWBCore: Resolve miscellaneous Swift 6 adoption issues
1 parent 26acb43 commit d065eb8

21 files changed

+171
-113
lines changed

Sources/SWBApplePlatform/InterfaceBuilderCompiler.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,20 @@
1313
import SWBUtil
1414
public import SWBCore
1515
public import SWBMacro
16+
import Synchronization
1617

1718
public class IbtoolCompilerSpec : GenericCompilerSpec, IbtoolCompilerSupport, @unchecked Sendable {
1819
/// The info object collects information across the build phase so that an ibtool task doesn't try to produce a ~device output which is already being explicitly produced from another input.
19-
private final class BuildPhaseInfo: BuildPhaseInfoForToolSpec {
20-
var allInputFilenames = Set<String>()
20+
private final class BuildPhaseInfo: BuildPhaseInfoForToolSpec, Sendable {
21+
let allInputFilenames = SWBMutex<Set<String>>([])
2122

2223
func addToContext(_ ftb: FileToBuild) {
2324
// Only collect info about files we want to match against.
2425
// FIXME: We should be using FileTypeSpec.conformsTo() here, but we don't have a good way in this context to look up the file type.
2526
guard ftb.fileType.identifier == "file.xib" else {
2627
return
2728
}
28-
allInputFilenames.insert(ftb.absolutePath.basenameWithoutSuffix)
29+
allInputFilenames.withLock{ $0.insert(ftb.absolutePath.basenameWithoutSuffix) }
2930
}
3031

3132
func filterOutputFiles(_ outputs: [any PlannedNode], inputs: [Path]) -> [any PlannedNode] {
@@ -40,7 +41,7 @@ public class IbtoolCompilerSpec : GenericCompilerSpec, IbtoolCompilerSupport, @u
4041
}
4142

4243
// If this output filename is among any of the input filenames that *aren't* one of our own inputs, then we remove it.
43-
let otherInputFilenames = allInputFilenames.subtracting(inputFilenames)
44+
let otherInputFilenames = allInputFilenames.withLock({ $0.subtracting(inputFilenames) })
4445
guard !otherInputFilenames.contains(outputFilename) else {
4546
return false
4647
}

Sources/SWBCore/Apple/DeviceFamily.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public struct DeviceFamily: Decodable, Hashable, Sendable {
8282
}
8383
}
8484

85-
public struct DeviceFamilies: Hashable {
85+
public struct DeviceFamilies: Hashable, Sendable {
8686
@_spi(Testing) public let list: [DeviceFamily]
8787

8888
/// Used for platforms where a numeric `UIDeviceFamily` value is not used, but a device family name must still be passed to asset processing tools via the `--target-device` flag. Mutually exclusive with `deviceFamiliesByIdentifier`.

Sources/SWBCore/Core.swift

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ public final class Core: Sendable {
116116
await core.initializeToolchainRegistry()
117117

118118
// Force loading SDKs.
119+
let sdkPaths = core.platformRegistry.platforms.flatMap { platform in platform.sdkSearchPaths.map { ($0, platform) } }
120+
core._sdkRegistry.initialize(to: SDKRegistry(delegate: core.registryDelegate, searchPaths: sdkPaths, type: .builtin, hostOperatingSystem: hostOperatingSystem))
119121
let sdkRegistry = core.sdkRegistry
120122

121123
struct Context: SDKRegistryExtensionAdditionalSDKsContext {
@@ -143,8 +145,8 @@ public final class Core: Sendable {
143145

144146
// FIXME: <rdar://problem/36364112> We should also perform late binding of the toolchains' settings here. Presently this is done when a Settings object which uses a toolchain is constructed.
145147

146-
// Force loading the CoreSettings (which can emit errors about missing required specs).
147-
let _ = core.coreSettings
148+
// Initialize the CoreSettings (which can emit errors about missing required specs).
149+
core._coreSettings.initialize(to: CoreSettings(core))
148150

149151
// If there were any loading errors, discard the core.
150152
if delegate.hasErrors {
@@ -308,9 +310,10 @@ public final class Core: Sendable {
308310
}
309311

310312
/// The shared core settings object.
311-
@_spi(Testing) public lazy var coreSettings: CoreSettings = {
312-
return CoreSettings(self)
313-
}()
313+
let _coreSettings = UnsafeDelayedInitializationSendableWrapper<CoreSettings>()
314+
@_spi(Testing) public var coreSettings: CoreSettings {
315+
_coreSettings.value
316+
}
314317

315318
/// The list of plugin search paths.
316319
private static func pluginPaths(inferiorProductsPath: Path?, developerPath: DeveloperPath) -> [Path] {
@@ -361,13 +364,8 @@ public final class Core: Sendable {
361364
return result.map { $0.normalize() }
362365
}
363366

364-
/// The list of SDK search paths.
365-
@_spi(Testing) public lazy var sdkPaths: [(Path, Platform?)] = {
366-
return self.platformRegistry.platforms.flatMap { platform in platform.sdkSearchPaths.map { ($0, platform) } }
367-
}()
368-
369367
/// The list of toolchain search paths.
370-
@_spi(Testing) public var toolchainPaths: [ToolchainRegistry.SearchPath]
368+
@_spi(Testing) public let toolchainPaths: [ToolchainRegistry.SearchPath]
371369

372370
/// The platform registry.
373371
let _platformRegistry: UnsafeDelayedInitializationSendableWrapper<PlatformRegistry> = .init()
@@ -380,12 +378,16 @@ public final class Core: Sendable {
380378
}
381379

382380
/// The SDK registry for Xcode's builtin SDKs. Clients should generally use `WorkspaceContext.sdkRegistry` to include dynamically discovered SDKs.
383-
public lazy var sdkRegistry: SDKRegistry = {
384-
return SDKRegistry(delegate: self.registryDelegate, searchPaths: self.sdkPaths, type: .builtin, hostOperatingSystem: hostOperatingSystem)
385-
}()
381+
let _sdkRegistry = UnsafeDelayedInitializationSendableWrapper<SDKRegistry>()
382+
public var sdkRegistry: SDKRegistry {
383+
_sdkRegistry.value
384+
}
386385

387386
/// The toolchain registry.
388-
public private(set) var toolchainRegistry: ToolchainRegistry! = nil
387+
let _toolchainRegistry = UnsafeDelayedInitializationSendableWrapper<ToolchainRegistry>()
388+
public var toolchainRegistry: ToolchainRegistry {
389+
_toolchainRegistry.value
390+
}
389391

390392
private let libclangRegistry = Registry<Path, (Libclang?, Version?)>()
391393
private let stopAfterOpeningLibClang: Bool
@@ -427,16 +429,11 @@ public final class Core: Sendable {
427429
}
428430

429431
/// The specification registry.
432+
private let _specRegistry = UnsafeDelayedInitializationSendableWrapper<SpecRegistry>()
430433
public var specRegistry: SpecRegistry {
431-
guard let specRegistry = _specRegistry else {
432-
// FIXME: We should structure the initialization path better and remove reliance on `lazy var` so that this can be handled more cleanly.
433-
preconditionFailure("Spec registry not initialized.")
434-
}
435-
return specRegistry
434+
return _specRegistry.value
436435
}
437436

438-
private var _specRegistry: SpecRegistry?
439-
440437
@_spi(Testing) public func initializePlatformRegistry() async {
441438
var searchPaths: [Path]
442439
let fs = localFS
@@ -466,19 +463,17 @@ public final class Core: Sendable {
466463

467464

468465
private func initializeToolchainRegistry() async {
469-
self.toolchainRegistry = await ToolchainRegistry(delegate: self.registryDelegate, searchPaths: self.toolchainPaths, fs: localFS, hostOperatingSystem: hostOperatingSystem)
466+
self._toolchainRegistry.initialize(to: await ToolchainRegistry(delegate: self.registryDelegate, searchPaths: self.toolchainPaths, fs: localFS, hostOperatingSystem: hostOperatingSystem))
470467
}
471468

472469
@_spi(Testing) public func initializeSpecRegistry() async {
473-
precondition(_specRegistry == nil)
474-
475470
var domainInclusions: [String: [String]] = [:]
476471

477472
// Compute the complete list of search paths (and default domains).
478473
var searchPaths = additionalContentPaths.map { ($0, "") }
479474

480475
// Find all plugin provided specs.
481-
for ext in await self.pluginManager.extensions(of: SpecificationsExtensionPoint.self) {
476+
for ext in self.pluginManager.extensions(of: SpecificationsExtensionPoint.self) {
482477
if let bundle = ext.specificationFiles(resourceSearchPaths: resourceSearchPaths) {
483478
for url in bundle.urls(forResourcesWithExtension: "xcspec", subdirectory: nil) ?? [] {
484479
do {
@@ -498,7 +493,7 @@ public final class Core: Sendable {
498493
}
499494
}
500495

501-
_specRegistry = await SpecRegistry(self.pluginManager, self.registryDelegate, searchPaths, domainInclusions, [:])
496+
_specRegistry.initialize(to: await SpecRegistry(self.pluginManager, self.registryDelegate, searchPaths, domainInclusions, [:]))
502497
}
503498

504499
/// Force all specs to be loaded.

Sources/SWBCore/Extensions/SettingsBuilderExtension.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public struct SettingsBuilderExtensionPoint: ExtensionPoint {
2323
public init() {}
2424
}
2525

26-
public protocol SettingsBuilderExtension {
26+
public protocol SettingsBuilderExtension: Sendable {
2727
/// Provides a table of additional build properties overrides
2828
func addOverrides(fromEnvironment: [String:String], parameters: BuildParameters) throws -> [String:String]
2929

Sources/SWBCore/FileToBuild.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public import SWBProtocol
1515
public import SWBMacro
1616

1717
/// Represents a file to be passed as input to some part of the build machinery. May be a source file originally sent down with the PIF, or might be a temporary file. Once a build rule action has been determined, it is assigned to the FileToBuild so it doesn’t have to be looked up again. Note that the term “file” here is used in the loosest sense — the path can refer to any file system entity.
18-
public struct FileToBuild : Hashable {
18+
public struct FileToBuild : Hashable, Sendable {
1919
/// Absolute path of the referenced file.
2020
public let absolutePath: Path
2121

Sources/SWBCore/LinkageDependencyResolver.swift

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,19 @@ actor LinkageDependencyResolver {
161161

162162
// Even though we do not want to include target dependencies in the graph, we still need to traverse them.
163163
let linkedTargets = linkageDependencies.map { $0.target.target }
164-
let targetDependencies: [ResolvedTargetDependency] = await resolver.explicitDependencies(for: configuredTarget).asyncMap { target in
164+
var targetDependencies: [ResolvedTargetDependency] = []
165+
for target in resolver.explicitDependencies(for: configuredTarget) {
165166
guard !linkedTargets.contains(target) else {
166-
return nil
167+
continue
167168
}
168169
let buildParameters = resolver.buildParametersByTarget[target] ?? configuredTarget.parameters
169-
if await !resolver.isTargetSuitableForPlatformForIndex(target, parameters: buildParameters, imposedParameters: imposedParameters) {
170-
return nil
170+
if !resolver.isTargetSuitableForPlatformForIndex(target, parameters: buildParameters, imposedParameters: imposedParameters) {
171+
continue
171172
}
172173
let effectiveImposedParameters = imposedParameters?.effectiveParameters(target: configuredTarget, dependency: ConfiguredTarget(parameters: buildParameters, target: target), dependencyResolver: resolver)
173174
let configuredDependency = await resolver.lookupConfiguredTarget(target, parameters: buildParameters, imposedParameters: effectiveImposedParameters)
174-
return ResolvedTargetDependency(target: configuredDependency, reason: .explicit)
175-
}.compactMap { $0 }
175+
targetDependencies.append(ResolvedTargetDependency(target: configuredDependency, reason: .explicit))
176+
}
176177
let dependencies = linkageDependencies + targetDependencies
177178

178179
// If we have no dependencies, we are done.
@@ -465,23 +466,23 @@ actor LinkageDependencyResolver {
465466
}
466467

467468
private func implicitDependency(forModuleName moduleName: String, from configuredTarget: ConfiguredTarget, imposedParameters: SpecializationParameters?, source: ImplicitDependencySource) async -> ConfiguredTarget? {
468-
let candidateConfiguredTargets = await (targetsByUnconfiguredModuleName[moduleName] ?? []).asyncMap { [self] candidateTarget -> ConfiguredTarget? in
469+
var candidateConfiguredTargets: [ConfiguredTarget] = []
470+
for candidateTarget in (targetsByUnconfiguredModuleName[moduleName] ?? []) {
469471
// Prefer overriding build parameters from the build request, if present.
470-
let buildParameters = resolver.buildParametersByTarget[candidateTarget] ?? configuredTarget.parameters
472+
let buildParameters = self.resolver.buildParametersByTarget[candidateTarget] ?? configuredTarget.parameters
471473

472474
// Validate the module name using concrete parameters.
473-
let configuredModuleName = buildRequestContext.getCachedSettings(buildParameters, target: candidateTarget).globalScope.evaluate(BuiltinMacros.PRODUCT_MODULE_NAME)
475+
let configuredModuleName = self.resolver.buildRequestContext.getCachedSettings(buildParameters, target: candidateTarget).globalScope.evaluate(BuiltinMacros.PRODUCT_MODULE_NAME)
474476
if configuredModuleName != moduleName {
475-
return nil
477+
continue
476478
}
477479

478480
// Get a configured target for this target, and use it as the implicit dependency.
479-
if let candidateConfiguredTarget = await implicitDependency(candidate: candidateTarget, parameters: buildParameters, isValidFor: configuredTarget, imposedParameters: imposedParameters, resolver: resolver) {
480-
return candidateConfiguredTarget
481+
if let candidateConfiguredTarget = await self.implicitDependency(candidate: candidateTarget, parameters: buildParameters, isValidFor: configuredTarget, imposedParameters: imposedParameters, resolver: resolver) {
482+
candidateConfiguredTargets.append(candidateConfiguredTarget)
481483
}
482-
483-
return nil
484-
}.compactMap { $0 }.sorted()
484+
}
485+
candidateConfiguredTargets.sort()
485486

486487
emitAmbiguousImplicitDependencyWarningIfNeeded(for: configuredTarget, dependencies: candidateConfiguredTargets, from: source)
487488

0 commit comments

Comments
 (0)