Skip to content
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

Merged
merged 15 commits into from
Dec 13, 2023

Conversation

MaxDesiatov
Copy link
Contributor

@MaxDesiatov MaxDesiatov commented Dec 3, 2023

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 to PackageGraph, but was previously leaking out into PackageModel by passing the derivedXCTestPlatformProvider closure around. That prevented us from marking SupportedPlatforms as Hashable and marking any of Resolved* types as value types also Hashable. In the future, when we need to make them Sendable, passing mutable state captured in a closure could become problematic.

Modifications:

Add new PlatformVersionProvider type, which is a value type that can be easily made Hashable and Sendable. Instead of passing closures around, platform version computation code is now gathered in a single file (new PlatformVersionProvider.swift), with all possible context captured in its inner enum Implementation.

This new type is adopted by Resolved* types in the PackageGraph module, which actively uses minimum platform version computations.

Renamed func getDerived to func getSupportedPlatform, now that this function delegating to PlatformVersionProvider is declared on Resolved* types.

Result:

SupportedPlatforms type, which is nothing more than [SupportedPlatform] array with an additional closure, can be removed. Types that previously had properties of SupportedPlatforms can be easily converted to value types and made Hashable in a way that accounts for their content instead of class instance identity.

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.
@MaxDesiatov MaxDesiatov added concurrency no functional change No user-visible functional changes included modules graph Modules dependency resolution labels Dec 3, 2023
@MaxDesiatov MaxDesiatov self-assigned this Dec 3, 2023
Base automatically changed from maxd/package-condition to main December 5, 2023 16:59
Copy link
Contributor

@tomerd tomerd left a 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

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

1 similar comment
@tomerd
Copy link
Contributor

tomerd commented Dec 8, 2023

@swift-ci test windows

}
return platforms.first!.version

case .customXCTestMinimumDeploymentTargets(let customXCTestMinimumDeploymentTargets):
Copy link
Contributor

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?

Copy link
Contributor Author

@MaxDesiatov MaxDesiatov Dec 13, 2023

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 🙂

@MaxDesiatov MaxDesiatov requested a review from neonichu December 13, 2023 12:59
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

1 similar comment
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

@MaxDesiatov MaxDesiatov enabled auto-merge (squash) December 13, 2023 17:59
@MaxDesiatov MaxDesiatov merged commit 10be62b into main Dec 13, 2023
@MaxDesiatov MaxDesiatov deleted the maxd/platform-version-provider branch December 13, 2023 20:13
MaxDesiatov added a commit that referenced this pull request Dec 15, 2023
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`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
modules graph Modules dependency resolution no functional change No user-visible functional changes included
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants