Removing `-strict-concurrency=targeted`

Hello, Swift evolution!

I'd like to remove -strict-concurrency=targeted. Targeted concurrency checking is intended to enable Sendable checking in contexts that have explicitly adopted concurrency features, which serves as a mechanism for incrementally adopting concurrency checking in a given module. However, the -strict-concurrency flag predates upcoming features, which provide a general and more granular way to prepare a project for the next major language version. Based on feedback that I've seen, programmers are also confused when the same concurrency mistake is diagnosed in certain contexts but not others.

I believe facilitating incremental adoption of complete concurrency checking through upcoming features is more approachable than enabling "strict checking" only in certain contexts through -strict-concurrency=targeted. For example, the various data-race safety proposals undergoing the Swift evolution process now would provide the following progression of upcoming features to help folks work toward complete checking (and we can introduce more incremental steps via upcoming features if necessary/helpful):

  • InferSendableFromCaptures (pitched and ready for review) will have minor type inference changes, but will apply better Sendable inference for key-paths and function values, and therefore cause fewer Sendable diagnostics under complete concurrency checking.
  • DisableOutwardActorInference (accepted in SE-0401) removes a confusing inference rule for global actor isolation that propagates from property wrappers outward to the enclosing type.
  • GlobalConcurrency (under review in SE-0412) applies Sendable / isolation checking at the declaration and use sites of global and static variables.
  • IsolatedDefaultValues (awaiting review decision for SE-0411) enables Sendable / isolation checking for stored properties and initializers of global actor isolated types.

Enabling specific subsets of strict concurrency checking incrementally through upcoming features means that the final switch for complete concurrency checking will be far more approachable than turning it on wholesale. Personally, even when I turn on targeted concurrency checking, I find it easier to go through and fix specific classes of issues at once because it makes the migration feel a bit more mechanical.

In terms of staging in the removal, I would still allow -strict-concurrency=targeted or .enableExperimentalFeature("StrictConcurrency=targeted") to be used, but it would mean the same thing as minimal concurrency checking.

Thoughts? If you are currently using targeted concurrency checking, I would love to hear about your experience and why you chose it over complete concurrency checking.



As long as .enableExperimentalFeature("StrictConcurrency=complete") itself or an alternative or replacement knob with the equivalent "tell me about ALL the problems" functionality continues to exist, I'm very actively 100% and in favor :+1:.


IsolatedDefaultValues is proposed as an upcoming feature, but implemented as an experimental feature.

Yes, that's the standard development practice for features undergoing the Swift evolution process. I promote experimental features to upcoming features after they've been accepted.

1 Like

I'm currently using targeted only for test-targets where the concurrency checking between the "test target" and the "mocked-stuff target" is unnecessary and results in a bunch of practically-useless warnings.
Other than that, i'd always go for complete anyway.

I could very well modify those stuff to be truly Sendable, but that would just be to comply with the warnings. The non-test targets of the package are already using complete.

Overall this seems fine but suboptimal to me to remove targeted.

1 Like

I'll throw some support behind continuing to support -strict-concurrency=targeted.

At Airbnb, we currently have the -strict-concurrency=targeted flag enabled across our entire codebase. We like using targeted concurrency checks because it only applies to code that has explicitly adopted async / await, etc. We had very little code that had adopted async / await at the time we enabled this flag, so it was very easy for us to enable targeted concurrency checks within our codebase.

On the other hand, -strict-concurrency=strict applies to all code in the codebase. Within a large existing codebase (Airbnb's app codebase is 2M+ LOC), adopting strict concurrency checking would be a huge amount of work.

We like that we are able to enable targeted concurrency checking, because this means that any new code using async / await will have this concurrency checking enabled. This increases the correctness of any new code using async / await, and reduces the total amount of work in enabling strict concurrency checking in the future (since this portion of the code is already following the strict concurrency rules).


As another data point: Checked with SSWG members and none of the projects represented there are using this mode.

1 Like