@@ -109,16 +109,36 @@ fileprivate extension InitializeBuildResponse {
109109/// the `BuiltInBuildSystem` protocol. For external (aka. out-of-process, aka. BSP servers) build systems, this means
110110/// that we need to manage the external build system's lifetime.
111111private enum BuildSystemAdapter {
112- case builtIn( BuiltInBuildSystemAdapter )
112+ case builtIn( BuiltInBuildSystemAdapter , connectionToBuildSystem : any Connection )
113113 case external( ExternalBuildSystemAdapter )
114+
115+ /// Send a notification to the build server.
116+ func send( _ notification: some NotificationType ) async {
117+ switch self {
118+ case . builtIn( _, let connectionToBuildSystem) :
119+ connectionToBuildSystem. send ( notification)
120+ case . external( let external) :
121+ await external. send ( notification)
122+ }
123+ }
124+
125+ /// Send a request to the build server.
126+ func send< Request: RequestType > ( _ request: Request ) async throws -> Request . Response {
127+ switch self {
128+ case . builtIn( _, let connectionToBuildSystem) :
129+ return try await connectionToBuildSystem. send ( request)
130+ case . external( let external) :
131+ return try await external. send ( request)
132+ }
133+ }
114134}
115135
116136private extension BuildSystemKind {
117137 private static func createBuiltInBuildSystemAdapter(
118138 projectRoot: AbsolutePath ,
119139 messagesToSourceKitLSPHandler: any MessageHandler ,
120140 _ createBuildSystem: @Sendable ( _ connectionToSourceKitLSP: any Connection ) async throws -> BuiltInBuildSystem ?
121- ) async -> ( buildSystemAdapter : BuildSystemAdapter , connectionToBuildSystem : any Connection ) ? {
141+ ) async -> BuildSystemAdapter ? {
122142 let connectionToSourceKitLSP = LocalConnection ( receiverName: " BuildSystemManager " )
123143 connectionToSourceKitLSP. start ( handler: messagesToSourceKitLSPHandler)
124144
@@ -136,7 +156,7 @@ private extension BuildSystemKind {
136156 )
137157 let connectionToBuildSystem = LocalConnection ( receiverName: " Build system " )
138158 connectionToBuildSystem. start ( handler: buildSystemAdapter)
139- return ( . builtIn( buildSystemAdapter) , connectionToBuildSystem)
159+ return . builtIn( buildSystemAdapter, connectionToBuildSystem : connectionToBuildSystem)
140160 }
141161
142162 /// Create a `BuildSystemAdapter` that manages a build system of this kind and return a connection that can be used
@@ -146,7 +166,7 @@ private extension BuildSystemKind {
146166 options: SourceKitLSPOptions ,
147167 buildSystemTestHooks testHooks: BuildSystemTestHooks ,
148168 messagesToSourceKitLSPHandler: any MessageHandler
149- ) async -> ( buildSystemAdapter : BuildSystemAdapter , connectionToBuildSystem : any Connection ) ? {
169+ ) async -> BuildSystemAdapter ? {
150170 switch self {
151171 case . buildServer( projectRoot: let projectRoot) :
152172 let buildSystem = await orLog ( " Creating external build system " ) {
@@ -160,7 +180,7 @@ private extension BuildSystemKind {
160180 return nil
161181 }
162182 logger. log ( " Created external build server at \( projectRoot. pathString) " )
163- return ( . external( buildSystem) , buildSystem . connectionToBuildServer )
183+ return . external( buildSystem)
164184 case . compilationDatabase( projectRoot: let projectRoot) :
165185 return await Self . createBuiltInBuildSystemAdapter (
166186 projectRoot: projectRoot,
@@ -217,32 +237,26 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
217237 /// get `fileBuildSettingsChanged` and `filesDependenciesUpdated` callbacks.
218238 private var watchedFiles : [ DocumentURI : ( mainFile: DocumentURI , language: Language ) ] = [ : ]
219239
220- /// The connection through which the `BuildSystemManager` can send requests to the build system.
221- ///
222- /// Access to this property should generally go through the non-underscored version, which waits until the build
223- /// server is initialized so that no messages can be sent to the BSP server before initialization finishes.
224- private var _connectionToBuildSystem : Connection ?
240+ /// The build system adapter that is used to answer build system queries.
241+ private var buildSystemAdapter : BuildSystemAdapter ?
225242
226- /// The connection to the build system. Will not yield the connection until the build server is initialized,
227- /// preventing accidental sending of messages to the build server before it is initialized.
228- private var connectionToBuildSystem : Connection ? {
243+ /// The build system adapter after initialization finishes. When sending messages to the BSP server, this should be
244+ /// preferred over `buildSystemAdapter` because no messages must be sent to the build server before initialization
245+ /// finishes.
246+ private var buildSystemAdapterAfterInitialized : BuildSystemAdapter ? {
229247 get async {
230- // Wait until initialization finishes.
231248 _ = await initializeResult. value
232- return _connectionToBuildSystem
249+ return buildSystemAdapter
233250 }
234251 }
235252
236- /// The build system adapter that is used to answer build system queries.
237- private var buildSystemAdapter : BuildSystemAdapter ?
238-
239253 /// If the underlying build system is a `TestBuildSystem`, return it. Otherwise, `nil`
240254 ///
241255 /// - Important: For testing purposes only.
242256 package var testBuildSystem : TestBuildSystem ? {
243257 get async {
244258 switch buildSystemAdapter {
245- case . builtIn( let builtInBuildSystemAdapter) : return await builtInBuildSystemAdapter. testBuildSystem
259+ case . builtIn( let builtInBuildSystemAdapter, _ ) : return await builtInBuildSystemAdapter. testBuildSystem
246260 case . external: return nil
247261 case nil : return nil
248262 }
@@ -327,14 +341,12 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
327341 self . toolchainRegistry = toolchainRegistry
328342 self . options = options
329343 self . projectRoot = buildSystemKind? . projectRoot
330- let buildSystemAdapterAndConnection = await buildSystemKind? . createBuildSystemAdapter (
344+ self . buildSystemAdapter = await buildSystemKind? . createBuildSystemAdapter (
331345 toolchainRegistry: toolchainRegistry,
332346 options: options,
333347 buildSystemTestHooks: buildSystemTestHooks,
334348 messagesToSourceKitLSPHandler: WeakMessageHandler ( self )
335349 )
336- self . buildSystemAdapter = buildSystemAdapterAndConnection? . buildSystemAdapter
337- self . _connectionToBuildSystem = buildSystemAdapterAndConnection? . connectionToBuildSystem
338350
339351 // The debounce duration of 500ms was chosen arbitrarily without any measurements.
340352 self . filesDependenciesUpdatedDebouncer = Debouncer (
@@ -355,15 +367,15 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
355367 // TODO: Forward file watch patterns from this initialize request to the client
356368 // (https://github.com/swiftlang/sourcekit-lsp/issues/1671)
357369 initializeResult = Task { ( ) -> InitializeBuildResponse ? in
358- guard let _connectionToBuildSystem else {
370+ guard let buildSystemAdapter else {
359371 return nil
360372 }
361373 guard let buildSystemKind else {
362374 logger. fault ( " If we have a connectionToBuildSystem, we must have had a buildSystemKind " )
363375 return nil
364376 }
365377 let initializeResponse = await orLog ( " Initializing build system " ) {
366- try await _connectionToBuildSystem . send (
378+ try await buildSystemAdapter . send (
367379 InitializeBuildRequest (
368380 displayName: " SourceKit-LSP " ,
369381 version: " " ,
@@ -389,27 +401,26 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
389401 underlyingBuildSystem: legacyBuildServer,
390402 connectionToSourceKitLSP: legacyBuildServer. connectionToSourceKitLSP
391403 )
392- self . buildSystemAdapter = . builtIn( adapter)
393404 let connectionToBuildSystem = LocalConnection ( receiverName: " Legacy BSP server " )
394405 connectionToBuildSystem. start ( handler: adapter)
395- self . _connectionToBuildSystem = connectionToBuildSystem
406+ self . buildSystemAdapter = . builtIn ( adapter , connectionToBuildSystem: connectionToBuildSystem )
396407 }
397- _connectionToBuildSystem . send ( OnBuildInitializedNotification ( ) )
408+ await buildSystemAdapter . send ( OnBuildInitializedNotification ( ) )
398409 return initializeResponse
399410 }
400411 }
401412
402413 deinit {
403414 // Shut down the build server before closing the connection to it
404- Task { [ connectionToBuildSystem = _connectionToBuildSystem , initializeResult] in
405- guard let connectionToBuildSystem else {
415+ Task { [ buildSystemAdapter , initializeResult] in
416+ guard let buildSystemAdapter else {
406417 return
407418 }
408419 // We are accessing the raw connection to the build server, so we need to ensure that it has been initialized here
409420 _ = await initializeResult? . value
410421 await orLog ( " Sending shutdown request to build server " ) {
411- _ = try await connectionToBuildSystem . send ( BuildShutdownRequest ( ) )
412- connectionToBuildSystem . send ( OnBuildExitNotification ( ) )
422+ _ = try await buildSystemAdapter . send ( BuildShutdownRequest ( ) )
423+ await buildSystemAdapter . send ( OnBuildExitNotification ( ) )
413424 }
414425 }
415426 }
@@ -655,7 +666,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
655666 in target: BuildTargetIdentifier ,
656667 language: Language
657668 ) async throws -> FileBuildSettings ? {
658- guard let connectionToBuildSystem = await connectionToBuildSystem else {
669+ guard let buildSystemAdapter = await buildSystemAdapterAfterInitialized else {
659670 return nil
660671 }
661672 let request = TextDocumentSourceKitOptionsRequest (
@@ -670,7 +681,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
670681 // very quickly from `settings(for:language:)`.
671682 // https://github.com/apple/sourcekit-lsp/issues/1181
672683 let response = try await cachedSourceKitOptions. get ( request) { request in
673- try await connectionToBuildSystem . send ( request)
684+ try await buildSystemAdapter . send ( request)
674685 }
675686 guard let response else {
676687 return nil
@@ -713,7 +724,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
713724 else {
714725 return nil
715726 }
716- if await connectionToBuildSystem == nil {
727+ if buildSystemAdapter == nil {
717728 // If there is no build system and we only have the fallback build system, we will never get real build settings.
718729 // Consider the build settings non-fallback.
719730 settings. isFallback = false
@@ -768,7 +779,9 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
768779
769780 package func waitForUpToDateBuildGraph( ) async {
770781 await orLog ( " Waiting for build system updates " ) {
771- let _: VoidResponse ? = try await connectionToBuildSystem? . send ( WorkspaceWaitForBuildSystemUpdatesRequest ( ) )
782+ let _: VoidResponse ? = try await buildSystemAdapterAfterInitialized? . send (
783+ WorkspaceWaitForBuildSystemUpdatesRequest ( )
784+ )
772785 }
773786 // Handle any messages the build system might have sent us while updating.
774787 await self . messageHandlingQueue. async ( metadata: . stateChange) { } . valuePropagatingCancellation
@@ -836,7 +849,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
836849 }
837850
838851 package func prepare( targets: Set < BuildTargetIdentifier > ) async throws {
839- let _: VoidResponse ? = try await connectionToBuildSystem ? . send (
852+ let _: VoidResponse ? = try await buildSystemAdapterAfterInitialized ? . send (
840853 BuildTargetPrepareRequest ( targets: targets. sorted { $0. uri. stringValue < $1. uri. stringValue } )
841854 )
842855 await orLog ( " Calling fileDependenciesUpdated " ) {
@@ -855,13 +868,13 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
855868 }
856869
857870 private func buildTargets( ) async throws -> [ BuildTargetIdentifier : BuildTargetInfo ] {
858- guard let connectionToBuildSystem = await connectionToBuildSystem else {
871+ guard let buildSystemAdapter = await buildSystemAdapterAfterInitialized else {
859872 return [ : ]
860873 }
861874
862875 let request = WorkspaceBuildTargetsRequest ( )
863876 let result = try await cachedBuildTargets. get ( request) { request in
864- let buildTargets = try await connectionToBuildSystem . send ( request) . targets
877+ let buildTargets = try await buildSystemAdapter . send ( request) . targets
865878 let ( depths, dependents) = await self . targetDepthsAndDependents ( for: buildTargets)
866879 var result : [ BuildTargetIdentifier : BuildTargetInfo ] = [ : ]
867880 result. reserveCapacity ( buildTargets. count)
@@ -898,7 +911,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
898911 }
899912
900913 package func sourceFiles( in targets: Set < BuildTargetIdentifier > ) async throws -> [ SourcesItem ] {
901- guard let connectionToBuildSystem = await connectionToBuildSystem , !targets. isEmpty else {
914+ guard let buildSystemAdapter = await buildSystemAdapterAfterInitialized , !targets. isEmpty else {
902915 return [ ]
903916 }
904917
@@ -916,7 +929,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
916929
917930 let request = BuildTargetSourcesRequest ( targets: targets. sorted { $0. uri. stringValue < $1. uri. stringValue } )
918931 let response = try await cachedTargetSources. get ( request) { request in
919- try await connectionToBuildSystem . send ( request)
932+ try await buildSystemAdapter . send ( request)
920933 }
921934 return response. items
922935 }
@@ -1041,8 +1054,8 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
10411054 // MARK: Informing BuildSystemManager about changes
10421055
10431056 package func filesDidChange( _ events: [ FileEvent ] ) async {
1044- if let connectionToBuildSystem = await connectionToBuildSystem {
1045- connectionToBuildSystem . send ( OnWatchedFilesDidChangeNotification ( changes: events) )
1057+ if let buildSystemAdapter = await buildSystemAdapterAfterInitialized {
1058+ await buildSystemAdapter . send ( OnWatchedFilesDidChangeNotification ( changes: events) )
10461059 }
10471060
10481061 var targetsWithUpdatedDependencies: Set< BuildTargetIdentifier> = [ ]
0 commit comments