You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduce richer EnabledTrait model to handle thread-safe enabled traits computations (#9269)
This PR introduces the `EnabledTrait` model and associated
infrastructure to properly track and manage trait enablement throughout
the dependency resolution process. The new system replaces simple
string-based trait tracking with a rich model that maintains provenance
information about how and why each trait was enabled.
Fixes#9286
## Core Changes
### New `EnabledTrait` Model (EnabledTrait.swift)
Introduces three main components for tracking enabled traits for
packages:
**EnabledTrait** - Represents an individual enabled trait with:
- Trait name (used as the identifier)
- Set of `Setter` values tracking how the trait was enabled (via
command-line config, parent package, or another trait)
- Support for unifying traits with the same name by merging their setter
lists - it's important to note that this is usually done with an
`EnabledTrait` for a specific package, and that many packages can define
their own (unique) trait that shares a name with a trait from another
package but are treated as fundamentally different instances.
**EnabledTraits** - Collection wrapper around
`IdentifiableSet<EnabledTrait>` that:
- Automatically unifies traits with the same name when inserted
- Provides convenient set operations (union, intersection)
- Maintains enablement metadata while treating traits with the same name
as equal (merges `Setters` for traits of the same name)
**EnabledTraitsMap** - Thread-safe map storing enabled traits per
package that:
- Maps `PackageIdentity` to `EnabledTraits`, while maintaining a
thread-safe storage box of its properties to accommodate for loading
manifests in parallel
- Implicitly returns `["default"]` for packages with no explicitly
enabled traits
- Uses union behaviour: setting traits for the same package multiple
times accumulates all traits
- Tracks whether default traits have been explicitly disabled by a
parent package or trait configuration (set with `[]`).
- Tracks parent packages that request `default` trait usage for a
package dependency (whether it's been requested through explicitly
listing `default` as a trait, or if a trait specification is omitted)
The introduction of these models have also provided some API
conveniences:
**String Interoperability** - `EnabledTrait` and `EnabledTraits` provide
seamless string integration:
- `ExpressibleByStringLiteral` and `ExpressibleByArrayLiteral` for
natural initialization of enabled traits and sets of enabled traits:
`let enabledTrait: EnabledTrait = "foo"` or `let enabledTraits:
EnabledTraits = ["foo", "bar"]`
- Bidirectional string equality: `enabledTrait == "foo"` and `"foo" ==
enabledTrait` both work
- `EnabledTraitConvertible` protocol allows APIs to accept string
collections and auto-convert them to `EnabledTrait`
**Collection Protocol Support** - `EnabledTraits` conforms to
`Collection` with set-like operations (union, intersection, contains)
and overloaded methods that accept either `Collection<String>` or
`Collection<EnabledTrait>`, enabling flexible APIs that work with both
types
## Refactored Trait Handling (`Manifest+Traits.swift`)
- Replaced all `Set<String>` trait representations with richer
`EnabledTraits` model
- Updated validation methods to work with `EnabledTrait` instead of raw
strings
- Removed parentPackage parameters from validation (now tracked via
`EnabledTrait.Setter`)
- Improved type safety and metadata tracking throughout trait
calculation
### `Workspace+Traits.swift` (new file)
- Extracted trait-specific workspace operations
- `updateEnabledTraits(for:)` method determines enabled traits for
loaded manifests
- `updateEnabledTraits(forDependency:_:)` handles dependency-specific
trait propagation
## Bug Fixes
### Required Dependencies Calculation
**Problem**: During PubGrub dependency resolution, enabled traits were
being reset to defaults instead of propagating previously calculated
values when creating `DependencyResolutionNode` instances, which relied
on an accurate set of `enabledTraits`.
**Impact**: Wrong trait sets were considered when evaluating required
dependencies, leading to incorrect dependency graphs.
**Solution**: Properly propagate enabled traits through the `nodes()`
method for `PackageContainerConstraint`, which creates instances of
`DependencyResolutionNode` from these constraints during PubGrub
dependency resolution.
### IdentifiableSet Intersection
**Problem**: The intersection method created an empty set instead of
starting with self, causing loss of element data.
**Solution**: Changed `var result = Self()` to `var result = self` in
`IdentifiableSet.swift:86`, ensuring proper preservation of element data
during intersections.
### Test Improvements
- Separated traits tests into dedicated files:
- `ModulesGraphTests+Traits.swift`
- `WorkspaceTests+Traits.swift`
- `EnabledTraitTests.swift`
## Additional Improvements
- Enhanced `IdentifiableSet` with `remove(id:)` and `remove(_:)` methods
- Added `Workspace+Traits.swift` for trait-specific workspace operations
- Updated all package container implementations for proper trait
handling
0 commit comments