Skip to content

Assure trait-guarded dependencies are not included in resolution; precompute enabled traits before resolution #8852

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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5469b84
Fix for trait-guarded deps being included in resolution
bripeticca Jun 19, 2025
f67f3df
Comment cleanup
bripeticca Jun 19, 2025
0d46a4c
De-duplicate calculation of transitively enabled traits
bripeticca Jun 19, 2025
e6bc7e6
Precompute traits and persist to module graph load
bripeticca Jun 25, 2025
6a3d2bb
Fix trait tests to account for removal of guarded deps
bripeticca Jun 25, 2025
e5c9eb8
Precompute traits + modify tests
bripeticca Jun 26, 2025
3b28262
Remove instances of optional set of enabled traits
bripeticca Jul 3, 2025
c134113
Introduce new EnabledTraitsMap struct
bripeticca Jul 3, 2025
2398e7d
Move enabled traits map into Workspace
bripeticca Jul 3, 2025
1b1ba10
Merge branch 'main' into traitresolutionbug
bripeticca Jul 3, 2025
adf28f7
Cleanup; logging messages to help debug failing traits tests
bripeticca Jul 4, 2025
6c2ce58
Add trait configuration to calls on getActiveWorkspace
bripeticca Jul 8, 2025
cb6723e
Amend plugin command configuration of package graph
bripeticca Jul 9, 2025
307867f
Allow workspace to update its trait configuration
bripeticca Jul 9, 2025
eb36991
Add trait configuration to SwiftCommandState
bripeticca Jul 10, 2025
c0ecd4e
Ensure PackageGraphRoot.init has latest enabledTraitsMap
bripeticca Jul 10, 2025
e989978
Cleanup
bripeticca Jul 10, 2025
ad0b958
Move EnabledTraitsMap to its own file in PackageModel
bripeticca Jul 10, 2025
7e71383
Cleanup remaining comments/whitespace
bripeticca Jul 10, 2025
da91ac0
Add EnabledTraitsMap.swift to CMakeList
bripeticca Jul 11, 2025
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
6 changes: 0 additions & 6 deletions Sources/Commands/PackageCommands/APIDiff.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ struct APIDiff: AsyncSwiftCommand {
help: "One or more targets to include in the API comparison. If present, only the specified targets (and any products specified using `--products`) will be compared.")
var targets: [String] = []

@OptionGroup(visibility: .hidden)
package var traits: TraitOptions

@Option(name: .customLong("baseline-dir"),
help: "The path to a directory used to store API baseline files. If unspecified, a temporary directory will be used.")
var overrideBaselineDir: Basics.AbsolutePath?
Expand Down Expand Up @@ -106,7 +103,6 @@ struct APIDiff: AsyncSwiftCommand {
)
} else {
let buildSystem = try await swiftCommandState.createBuildSystem(
traitConfiguration: .init(traitOptions: self.traits),
cacheBuildManifest: false,
)
try await runWithSwiftPMCoordinatedDiffing(
Expand Down Expand Up @@ -207,7 +203,6 @@ struct APIDiff: AsyncSwiftCommand {
)
let delegate = DiagnosticsCapturingBuildSystemDelegate()
let buildSystem = try await swiftCommandState.createBuildSystem(
traitConfiguration: .init(traitOptions: self.traits),
cacheBuildManifest: false,
productsBuildParameters: productsBuildParameters,
delegate: delegate
Expand Down Expand Up @@ -316,7 +311,6 @@ struct APIDiff: AsyncSwiftCommand {
// Build the baseline module.
// FIXME: We need to implement the build tool invocation closure here so that build tool plugins work with the APIDigester. rdar://86112934
let buildSystem = try await swiftCommandState.createBuildSystem(
traitConfiguration: .init(),
cacheBuildManifest: false,
productsBuildParameters: productsBuildParameters,
packageGraphLoader: { graph }
Expand Down
2 changes: 1 addition & 1 deletion Sources/Commands/PackageCommands/DumpCommands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct DumpSymbolGraph: AsyncSwiftCommand {
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: .native,
// We are enabling all traits for dumping the symbol graph.
traitConfiguration: .init(enableAllTraits: true),
enableAllTraits: true,
cacheBuildManifest: false
)
try await buildSystem.build()
Expand Down
2 changes: 1 addition & 1 deletion Sources/Commands/PackageCommands/Install.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ extension SwiftPackageCommand {
commandState.preferredBuildConfiguration = .release
}

try await commandState.createBuildSystem(explicitProduct: productToInstall.name, traitConfiguration: .init())
try await commandState.createBuildSystem(explicitProduct: productToInstall.name)
.build(subset: .product(productToInstall.name))

let binPath = try commandState.productsBuildParameters.buildPath.appending(component: productToInstall.name)
Expand Down
1 change: 0 additions & 1 deletion Sources/Commands/PackageCommands/Migrate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ extension SwiftPackageCommand {
}

return try await swiftCommandState.createBuildSystem(
traitConfiguration: .init(),
// Don't attempt to cache manifests with temporary
// feature flags added just for migration purposes.
cacheBuildManifest: false,
Expand Down
1 change: 0 additions & 1 deletion Sources/Commands/PackageCommands/PluginCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ struct PluginCommand: AsyncSwiftCommand {
// Build or bring up-to-date any executable host-side tools on which this plugin depends. Add them and any binary dependencies to the tool-names-to-path map.
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: buildSystemKind,
traitConfiguration: .init(),
cacheBuildManifest: false,
productsBuildParameters: swiftCommandState.productsBuildParameters,
toolsBuildParameters: buildParameters,
Expand Down
10 changes: 3 additions & 7 deletions Sources/Commands/PackageCommands/Resolve.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ extension SwiftPackageCommand {

@Argument(help: "The name of the package to resolve.")
var packageName: String?

/// Specifies the traits to build.
@OptionGroup(visibility: .hidden)
package var traits: TraitOptions
}

struct Resolve: AsyncSwiftCommand {
Expand All @@ -50,10 +46,10 @@ extension SwiftPackageCommand {
func run(_ swiftCommandState: SwiftCommandState) async throws {
// If a package is provided, use that to resolve the dependencies.
if let packageName = resolveOptions.packageName {
let workspace = try swiftCommandState.getActiveWorkspace(traitConfiguration: .init(traitOptions: resolveOptions.traits))
let workspace = try swiftCommandState.getActiveWorkspace()
try await workspace.resolve(
packageName: packageName,
root: swiftCommandState.getWorkspaceRoot(traitConfiguration: .init(traitOptions: resolveOptions.traits)),
root: swiftCommandState.getWorkspaceRoot(),
version: resolveOptions.version,
branch: resolveOptions.branch,
revision: resolveOptions.revision,
Expand All @@ -64,7 +60,7 @@ extension SwiftPackageCommand {
}
} else {
// Otherwise, run a normal resolve.
try await swiftCommandState.resolve(.init(traitOptions: resolveOptions.traits))
try await swiftCommandState.resolve()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Commands/Snippets/Cards/SnippetCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ struct SnippetCard: Card {

func runExample() async throws {
print("Building '\(snippet.path)'\n")
let buildSystem = try await swiftCommandState.createBuildSystem(explicitProduct: snippet.name, traitConfiguration: .init())
let buildSystem = try await swiftCommandState.createBuildSystem(explicitProduct: snippet.name)
try await buildSystem.build(subset: .product(snippet.name))
let executablePath = try swiftCommandState.productsBuildParameters.buildPath.appending(component: snippet.name)
if let exampleTarget = try await buildSystem.getPackageGraph().module(for: snippet.name) {
Expand Down
6 changes: 0 additions & 6 deletions Sources/Commands/SwiftBuildCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,6 @@ struct BuildCommandOptions: ParsableArguments {
@OptionGroup(visibility: .private)
var testLibraryOptions: TestLibraryOptions

/// Specifies the traits to build.
@OptionGroup(visibility: .hidden)
package var traits: TraitOptions

/// If should link the Swift stdlib statically.
@Flag(name: .customLong("static-swift-stdlib"), inversion: .prefixedNo, help: "Link Swift stdlib statically.")
public var shouldLinkStaticSwiftStdlib: Bool = false
Expand Down Expand Up @@ -144,7 +140,6 @@ public struct SwiftBuildCommand: AsyncSwiftCommand {
// FIXME: Doesn't seem ideal that we need an explicit build operation, but this concretely uses the `LLBuildManifest`.
guard let buildOperation = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: .native,
traitConfiguration: .init(traitOptions: self.options.traits)
) as? BuildOperation else {
throw StringError("asked for native build system but did not get it")
}
Expand Down Expand Up @@ -194,7 +189,6 @@ public struct SwiftBuildCommand: AsyncSwiftCommand {
) async throws {
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitProduct: options.product,
traitConfiguration: .init(traitOptions: self.options.traits),
shouldLinkStaticSwiftStdlib: options.shouldLinkStaticSwiftStdlib,
productsBuildParameters: productsBuildParameters,
toolsBuildParameters: toolsBuildParameters,
Expand Down
10 changes: 2 additions & 8 deletions Sources/Commands/SwiftRunCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ struct RunCommandOptions: ParsableArguments {
@Argument(help: "The executable to run.", completion: .shellCommand("swift package completion-tool list-executables"))
var executable: String?

/// Specifies the traits to build the product with.
@OptionGroup(visibility: .hidden)
package var traits: TraitOptions

/// The arguments to pass to the executable.
@Argument(parsing: .captureForPassthrough,
help: "The arguments to pass to the executable.")
Expand Down Expand Up @@ -139,7 +135,6 @@ public struct SwiftRunCommand: AsyncSwiftCommand {
// FIXME: We need to implement the build tool invocation closure here so that build tool plugins work with the REPL. rdar://86112934
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: .native,
traitConfiguration: .init(traitOptions: self.options.traits),
cacheBuildManifest: false,
packageGraphLoader: asyncUnsafeGraphLoader
)
Expand All @@ -161,7 +156,6 @@ public struct SwiftRunCommand: AsyncSwiftCommand {
do {
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitProduct: options.executable,
traitConfiguration: .init(traitOptions: self.options.traits)
)
let productName = try await findProductName(in: buildSystem.getPackageGraph())
if options.shouldBuildTests {
Expand Down Expand Up @@ -217,9 +211,9 @@ public struct SwiftRunCommand: AsyncSwiftCommand {
do {
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitProduct: options.executable,
traitConfiguration: .init(traitOptions: self.options.traits)
)
let productName = try await findProductName(in: buildSystem.getPackageGraph())
let modulesGraph = try await buildSystem.getPackageGraph()
let productName = try findProductName(in: modulesGraph)
if options.shouldBuildTests {
try await buildSystem.build(subset: .allIncludingTests)
} else if options.shouldBuild {
Expand Down
11 changes: 2 additions & 9 deletions Sources/Commands/SwiftTestCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,6 @@ struct TestCommandOptions: ParsableArguments {
var enableExperimentalTestOutput: Bool {
return testOutput == .experimentalSummary
}

@OptionGroup(visibility: .hidden)
package var traits: TraitOptions
}

/// Tests filtering specifier, which is used to filter tests to run.
Expand Down Expand Up @@ -659,7 +656,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand {
productsBuildParameters: productsBuildParameters,
toolsBuildParameters: toolsBuildParameters,
testProduct: self.options.sharedOptions.testProduct,
traitConfiguration: .init(traitOptions: self.options.traits)
traitConfiguration: .init(traitOptions: self.globalOptions.traits)
)
}

Expand Down Expand Up @@ -741,9 +738,6 @@ extension SwiftTestCommand {
@OptionGroup()
var testEventStreamOptions: TestEventStreamOptions

@OptionGroup(visibility: .hidden)
package var traits: TraitOptions

// for deprecated passthrough from SwiftTestTool (parse will fail otherwise)
@Flag(name: [.customLong("list-tests"), .customShort("l")], help: .hidden)
var _deprecated_passthrough: Bool = false
Expand Down Expand Up @@ -850,7 +844,7 @@ extension SwiftTestCommand {
productsBuildParameters: productsBuildParameters,
toolsBuildParameters: toolsBuildParameters,
testProduct: self.sharedOptions.testProduct,
traitConfiguration: .init(traitOptions: self.traits)
traitConfiguration: .init(traitOptions: self.globalOptions.traits)
)
}
}
Expand Down Expand Up @@ -1561,7 +1555,6 @@ private func buildTestsIfNeeded(
traitConfiguration: TraitConfiguration
) async throws -> [BuiltTestProduct] {
let buildSystem = try await swiftCommandState.createBuildSystem(
traitConfiguration: traitConfiguration,
productsBuildParameters: productsBuildParameters,
toolsBuildParameters: toolsBuildParameters
)
Expand Down
1 change: 0 additions & 1 deletion Sources/Commands/Utilities/APIDigester.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ struct APIDigesterBaselineDumper {
// FIXME: We need to implement the build tool invocation closure here so that build tool plugins work with the APIDigester. rdar://86112934
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: .native,
traitConfiguration: .init(),
cacheBuildManifest: false,
productsBuildParameters: productsBuildParameters,
toolsBuildParameters: toolsBuildParameters,
Expand Down
5 changes: 2 additions & 3 deletions Sources/Commands/Utilities/PluginDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ final class PluginDelegate: PluginInvocationDelegate {
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: buildSystem,
explicitProduct: explicitProduct,
traitConfiguration: .init(),
cacheBuildManifest: false,
productsBuildParameters: buildParameters,
outputStream: outputStream,
Expand All @@ -181,6 +180,7 @@ final class PluginDelegate: PluginInvocationDelegate {
// Run the build. This doesn't return until the build is complete.
let success = await buildSystem.buildIgnoringError(subset: buildSubset)

swiftCommandState.observabilityScope.emit(warning: "plugin delegate getting package graph")
let packageGraph = try await buildSystem.getPackageGraph()

var builtArtifacts: [PluginInvocationBuildResult.BuiltArtifact] = []
Expand Down Expand Up @@ -246,7 +246,6 @@ final class PluginDelegate: PluginInvocationDelegate {
toolsBuildParameters.testingParameters.explicitlyEnabledTestability = true
toolsBuildParameters.testingParameters.enableCodeCoverage = parameters.enableCodeCoverage
let buildSystem = try await swiftCommandState.createBuildSystem(
traitConfiguration: .init(),
toolsBuildParameters: toolsBuildParameters
)
try await buildSystem.build(subset: .allIncludingTests)
Expand Down Expand Up @@ -410,7 +409,7 @@ final class PluginDelegate: PluginInvocationDelegate {
// Create a build system for building the target., skipping the the cache because we need the build plan.
let buildSystem = try await swiftCommandState.createBuildSystem(
explicitBuildSystem: buildSystem,
traitConfiguration: TraitConfiguration(enableAllTraits: true),
enableAllTraits: true,
cacheBuildManifest: false
)

Expand Down
16 changes: 8 additions & 8 deletions Sources/CoreCommands/BuildSystemSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private struct NativeBuildSystemFactory: BuildSystemFactory {

func makeBuildSystem(
explicitProduct: String?,
traitConfiguration: TraitConfiguration,
enableAllTraits: Bool,
cacheBuildManifest: Bool,
productsBuildParameters: BuildParameters?,
toolsBuildParameters: BuildParameters?,
Expand All @@ -39,7 +39,7 @@ private struct NativeBuildSystemFactory: BuildSystemFactory {
observabilityScope: ObservabilityScope?,
delegate: BuildSystemDelegate?
) async throws -> any BuildSystem {
_ = try await swiftCommandState.getRootPackageInformation(traitConfiguration: traitConfiguration)
_ = try await swiftCommandState.getRootPackageInformation(enableAllTraits)
let testEntryPointPath = productsBuildParameters?.testProductStyle.explicitlySpecifiedEntryPointPath
let cacheBuildManifest = if cacheBuildManifest {
try await self.swiftCommandState.canUseCachedBuildManifest()
Expand All @@ -53,7 +53,7 @@ private struct NativeBuildSystemFactory: BuildSystemFactory {
packageGraphLoader: packageGraphLoader ?? {
try await self.swiftCommandState.loadPackageGraph(
explicitProduct: explicitProduct,
traitConfiguration: traitConfiguration,
enableAllTraits: enableAllTraits,
testEntryPointPath: testEntryPointPath
)
},
Expand All @@ -63,7 +63,7 @@ private struct NativeBuildSystemFactory: BuildSystemFactory {
disableSandbox: self.swiftCommandState.shouldDisableSandbox
),
scratchDirectory: self.swiftCommandState.scratchDirectory,
traitConfiguration: traitConfiguration,
traitConfiguration: enableAllTraits ? .enableAllTraits : self.swiftCommandState.traitConfiguration,
additionalFileRules: FileRuleDescription.swiftpmFileTypes,
pkgConfigDirectories: self.swiftCommandState.options.locations.pkgConfigDirectories,
outputStream: outputStream ?? self.swiftCommandState.outputStream,
Expand All @@ -79,7 +79,7 @@ private struct XcodeBuildSystemFactory: BuildSystemFactory {

func makeBuildSystem(
explicitProduct: String?,
traitConfiguration: TraitConfiguration,
enableAllTraits: Bool,
cacheBuildManifest: Bool,
productsBuildParameters: BuildParameters?,
toolsBuildParameters: BuildParameters?,
Expand All @@ -94,7 +94,7 @@ private struct XcodeBuildSystemFactory: BuildSystemFactory {
packageGraphLoader: packageGraphLoader ?? {
try await self.swiftCommandState.loadPackageGraph(
explicitProduct: explicitProduct,
traitConfiguration: traitConfiguration
enableAllTraits: enableAllTraits
)
},
outputStream: outputStream ?? self.swiftCommandState.outputStream,
Expand All @@ -111,7 +111,7 @@ private struct SwiftBuildSystemFactory: BuildSystemFactory {

func makeBuildSystem(
explicitProduct: String?,
traitConfiguration: TraitConfiguration,
enableAllTraits: Bool,
cacheBuildManifest: Bool,
productsBuildParameters: BuildParameters?,
toolsBuildParameters: BuildParameters?,
Expand All @@ -126,7 +126,7 @@ private struct SwiftBuildSystemFactory: BuildSystemFactory {
packageGraphLoader: packageGraphLoader ?? {
try await self.swiftCommandState.loadPackageGraph(
explicitProduct: explicitProduct,
traitConfiguration: traitConfiguration,
enableAllTraits: enableAllTraits,
)
},
packageManagerResourcesDirectory: swiftCommandState.packageManagerResourcesDirectory,
Expand Down
13 changes: 8 additions & 5 deletions Sources/CoreCommands/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public struct GlobalOptions: ParsableArguments {

@OptionGroup(title: "Build Options")
public var linker: LinkerOptions

@OptionGroup(title: "Trait Options")
public var traits: TraitOptions
}

public struct LocationOptions: ParsableArguments {
Expand Down Expand Up @@ -683,8 +686,8 @@ public struct TestLibraryOptions: ParsableArguments {
}
}

package struct TraitOptions: ParsableArguments {
package init() {}
public struct TraitOptions: ParsableArguments {
public init() {}

/// The traits to enable for the package.
@Option(
Expand All @@ -694,7 +697,7 @@ package struct TraitOptions: ParsableArguments {
package var _enabledTraits: String?

/// The set of enabled traits for the package.
package var enabledTraits: Set<String>? {
public var enabledTraits: Set<String>? {
self._enabledTraits.flatMap { Set($0.components(separatedBy: ",")) }
}

Expand All @@ -703,7 +706,7 @@ package struct TraitOptions: ParsableArguments {
name: .customLong("enable-all-traits"),
help: "Enables all traits of the package."
)
package var enableAllTraits: Bool = false
public var enableAllTraits: Bool = false

/// Disables all default traits of the package.
@Flag(
Expand All @@ -714,7 +717,7 @@ package struct TraitOptions: ParsableArguments {
}

extension TraitConfiguration {
package init(traitOptions: TraitOptions) {
public init(traitOptions: TraitOptions) {
var enabledTraits = traitOptions.enabledTraits
if traitOptions.disableDefaultTraits {
// If there are no enabled traits specified we can disable the
Expand Down
Loading