-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
[NFC] Remove SupportedPlatforms
, add PlatformVersionProvider
#7161
Conversation
Multiple places in our codebase pass around and store `[any PackageConditionProtocol]` arrays of existentials with `FIXME` notes that those should be sets and not arrays. Adding `Hashable` requirement to `PackageConditionProtocol` doesn't fix the issue, since existentials of this protocol still wouldn't conform to `Hashable`. A simple alternative is to create `enum PackageCondition` with cases for each condition type. We only have two of those types and they're always declared in the same package. There's no use case for externally defined types for this protocol. That allows us to convert uses of `[any PackageConditionProtocol]` to `Set<PackageCondition>`. Existing protocol kept around until clients of SwiftPM can migrate to the new `PackageCondition` enum.
Depends on #7117, unblocks #7160. The `PackageModel` module has no business of defining supported platforms computation for resolved targets, products, and packages. This belongs to `PackageGraph`, but was previously leaking out into `PackageModel` by passing the `derivedXCTestPlatformProvider` closure around. That prevented us from converting marking `SupportedPlatforms` as `Hashable` and marking any of `Resolved*` types as value types and also `Hashable`. In the future, when we'll also need to make them `Sendable`, this could become problematic, passing so much state captured in a closure, mostly by accident.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code changes seem fine, @neonichu is more familiar with the logic so would be good for him to review
@swift-ci test |
@swift-ci test windows |
@swift-ci test |
@swift-ci test |
@swift-ci test windows |
1 similar comment
@swift-ci test windows |
} | ||
return platforms.first!.version | ||
|
||
case .customXCTestMinimumDeploymentTargets(let customXCTestMinimumDeploymentTargets): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are creating the implementation enum here, I wonder if we should make custom and default two separate cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I also found that Implementation.empty
case is unused. Ready for review 🙂
@swift-ci test |
@swift-ci test windows |
@swift-ci test |
@swift-ci test windows |
1 similar comment
@swift-ci test windows |
Depends on #7161. Unblocks macros cross-compilation fix in #7118. ### Motivation: Value types are easier to reason about as they prevent "spooky action at a distance" bugs, and can be easily made `Equatable`, `Hashable`, and most important of all `Sendable`. ### Modifications: Converted `ResolvedTarget`, `ResolvedProduct`, and `ResolvedPackage` from `final class`es to `struct`s. Renamed `underlyingTarget`, `underlyingProduct`, and `underlyingPackage` to just `underlying` to avoid tautological patterns like `target.underlyingTarget`. ### Result: It's easier to apply changes in `PackageGraph`. Also, in my benchmarks done locally this makes package graph resolution consistently ~5% faster when resolving the package graph of SwiftPM's own `Package.swift`. #### `main` branch: ``` ╒══════════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕ │ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │ ╞══════════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡ │ Time (system CPU) (ms) │ 7 │ 8 │ 11 │ 14 │ 15 │ 18 │ 18 │ 25 │ ├──────────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Time (total CPU) (ms) │ 12 │ 13 │ 16 │ 19 │ 20 │ 23 │ 23 │ 25 │ ├──────────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Time (user CPU) (μs) │ 4688 │ 4857 │ 4890 │ 4956 │ 5107 │ 5347 │ 5347 │ 25 │ ├──────────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Time (wall clock) (ms) │ 390 │ 397 │ 402 │ 409 │ 414 │ 420 │ 420 │ 25 │ ╘══════════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛ ``` #### This PR's branch: ``` ╒══════════════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕ │ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │ ╞══════════════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡ │ Time (system CPU) (ms) │ 6 │ 8 │ 10 │ 13 │ 16 │ 17 │ 17 │ 26 │ ├──────────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Time (total CPU) (ms) │ 11 │ 13 │ 15 │ 18 │ 20 │ 21 │ 21 │ 26 │ ├──────────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Time (user CPU) (μs) │ 4476 │ 4567 │ 4648 │ 4796 │ 4931 │ 4998 │ 4998 │ 26 │ ├──────────────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Time (wall clock) (ms) │ 375 │ 379 │ 384 │ 391 │ 394 │ 398 │ 398 │ 26 │ ╘══════════════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛ ``` ### Future directions: I'm unable to fully remove `Resolved*Builder` classes yet, as they rely on `Target` being a reference type and module aliasing relying on side effects of modifying instances of `Target`. In turn, `Target` is a class hierarchy, which we should convert to multiple value types that use composition in the future. In the meantime this also prevents us from making it, and all types that contain it, `Sendable`.
Unblocks
PackageGraph
value types refactoring in #7160 and macros cross-compilation fix in #7118.Motivation:
The
PackageModel
module has no business of defining supported platforms computation for resolved targets, products, and packages. This belongs toPackageGraph
, but was previously leaking out intoPackageModel
by passing thederivedXCTestPlatformProvider
closure around. That prevented us from markingSupportedPlatforms
asHashable
and marking any ofResolved*
types as value types alsoHashable
. In the future, when we need to make themSendable
, passing mutable state captured in a closure could become problematic.Modifications:
Add new
PlatformVersionProvider
type, which is a value type that can be easily madeHashable
andSendable
. Instead of passing closures around, platform version computation code is now gathered in a single file (newPlatformVersionProvider.swift
), with all possible context captured in its innerenum Implementation
.This new type is adopted by
Resolved*
types in thePackageGraph
module, which actively uses minimum platform version computations.Renamed
func getDerived
tofunc getSupportedPlatform
, now that this function delegating toPlatformVersionProvider
is declared onResolved*
types.Result:
SupportedPlatforms
type, which is nothing more than[SupportedPlatform]
array with an additional closure, can be removed. Types that previously had properties ofSupportedPlatforms
can be easily converted to value types and madeHashable
in a way that accounts for their content instead of class instance identity.