Concurrency Checking in Swift Packages (unsafeFlags)

With Swift 5.7 one can enable concurrency checking within Package.swift with .unsafeFlags() which introduces the limitations outlined in this thread.

The workaround I am currently using is via dynamic settings keyed off the presence of an environment variable:

  .target(
    name: "MyModule",
    swiftSettings: .concurrencyChecking
  )
extension Array where Element == SwiftSetting {
  static var concurrencyChecking: [SwiftSetting] {
    if Context.environment["ENABLE_STRICT_CONCURRENCY"] != nil {
      return [SwiftSetting.unsafeFlags(["-Xfrontend", "-strict-concurrency=complete"])]
    } else {
      return []
    }
  }
}

Setting an environment variable in the shell and building with % swift build activates the unsafeFlags while builds via Xcode does not.

This works great for enabling concurrency checking via build scripts (CI) but is there any way to enable this checking within Xcode for developers performing local edits?

3 Likes

SE-0362 allows for this checking to be enabled with the flag -enable-upcoming-feature StrictConcurrency

The nightlies currently treat this as an unsafeFlag but it looks like that is a bug.

With the release of Swift 5.8 this is now possible but requires that Package.swift use swift-tools-version:5.8:

// swift-tools-version:5.8

import PackageDescription

let package = Package(
  name: "Awaiting",
  platforms: [.macOS(.v10_15), .iOS(.v13)],
  products: [
    .library(
      name: "Awaiting",
      targets: ["Awaiting"]
    )
  ],
  targets: [
    .target(
      name: "Awaiting",
      path: "Sources",
      swiftSettings: [.enableUpcomingFeature("StrictConcurrency")]
    )
  ]
)

Compiler checks #if swift(>=5.8) do not work — // swift-tools-version:5.8 must be specified.

3 Likes

Interestingly this doesn't seem to work for me. Using .enableUpcomingFeature("StrictConcurrency"), in a target in my Package file doesn't show any warnings, but using .unsafeFlags(["-Xfrontend", "-warn-concurrency"]) does show a bunch.
With Xcode Version 14.3 (14E222b) and Swift version 5.8.

Not sure if I'm doing something wrong?

1 Like

I did find that a clean build was required when I added the upcoming feature.

1 Like

Same here: .enableUpcomingFeature("StrictConcurrency") doesn't show any warnings for me, whereas .unsafeFlags(["-Xfrontend", "-warn-concurrency"]) or .unsafeFlags(["-Xfrontend", "-strict-concurrency=complete"]) does show warnings.

If I'm reading the compiler source code correctly, it cannot work because StrictConcurrency is not defined as an upcoming feature flag at all.

Here's the relevant code in Features.def:

  1. In the release/5.8 branch:

    UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
    UPCOMING_FEATURE(ForwardTrailingClosures, 286, 6)
    UPCOMING_FEATURE(BareSlashRegexLiterals, 354, 6)
    UPCOMING_FEATURE(ExistentialAny, 335, 6)
    
  2. In the main branch (release/5.9 is identical):

    UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
    UPCOMING_FEATURE(ForwardTrailingClosures, 286, 6)
    UPCOMING_FEATURE(BareSlashRegexLiterals, 354, 6)
    UPCOMING_FEATURE(ExistentialAny, 335, 6)
    UPCOMING_FEATURE(ImportObjcForwardDeclarations, 384, 6)
    

Besides StrictConcurrency, the other missing feature flag that's explicitly mentioned in SE-0362 is ImplicitOpenExistentials.

3 Likes

I believe this thread is conflating prerelease feature flags (flags in the compiler while a feature is under development) and upcoming feature flags (features which will be enabled in a future version of Swift, usually 6). Upcoming features with flags are flagged because they may include source breakages or are otherwise large changes. I believe the proposal which formalized such flags didn't do a great job of differentiating between the two use cases, so it's not clear when proposals use one type of flag or the other. But that's likely the case here.

I don't think we're conflating these. If you follow the links to Features.def I posted above, the file distinguishes between UPCOMING_FEATURE and EXPERIMENTAL_FEATURE. We're only talking about the former. SE-0362 lists 6 upcoming features. These are all non-experimental features that went through Swift Evolution.

For whatever reason, only 4 of those 6 upcoming features have working feature flags in Swift 5.8. To be fair, this matches with what's documented in the Swift 5.8 intro blog post on swift.org (as far as I can tell, the changelog on GitHub only lists 3 of the 4 features).

I can't speak to ImplicitOpenExistentials (maybe the semantics change mentioned in SE-0362 isn't implemented yet?), but for StrictConcurrency this seems like an oversight because we know for a fact that a flag for strict concurrency checking exists, it just doesn't seem to be working with the new feature flag mechanism.

3 Likes

Ah true. Guess I don't understand why StrictConcurrency is a flag at all when it has an equivalent, but it is called out in the proposal.

1 Like

Maybe file a bug report? This blocks enabling this in SPM dependencies after all…

Is that true? For remote dependencies you don't want this enabled, as it just produces diagnostics you can't fix. For local development dependencies you can use the unsafe flag version, as SPM doesn't care if you use those in unversioned dependencies (IIRC).

The evolution proposals with upcoming feature flags have all been updated with an Upcoming Feature Flag field and a description of what it does in the Source Compatibility section of the proposal.

I don't know why the StrictConcurrency flag was not added, but I was guessing it may be because the existing -strict-concurrency compiler flag can either be set to either targeted or complete so has more functionality than a simple on/off flag.

FYI, on the Swift Evolution dashboard, upcoming feature flags are now displayed for proposals that have one and can be searched for by name. There is currently a PR to add a filter to show proposals with an upcoming feature flag.

1 Like

Well, we use versioning extensively internally and have a case to systematically turn on swift 6 flags (especially concurrency checking) across a wide range of versioned repos. Some might be open source as well and it’d be nice to turn these checks on in a systemic manner. Maybe I’m missing something but that’s our thoughts.

1 Like

FYI, Add the missing StrictConcurrency upcoming feature flag by gwynne · Pull Request #65993 · apple/swift · GitHub

2 Likes