Pre-Pitch: compiler support for showing concurrency information in Xcode

I'd like to propose a Xcode feature which helps user to determine where an func runs or which actor a property belong to. This is a pre-pitch for adding compiler support for it.

Note: since I don't know compiler internals, this pre-pitch is more like a software requirement document, not a design document.

How it will work in Xcode

The feature will work in Xcode in a similar way as how we view a variable's type using Alt-click. I'll use the following code as an example.

1       import SwiftUI

2       struct ContentView: View {
3           @State var data = "Hello"

4           var body: some View {
5               VStack(spacing: 16) {
6                   Button("Test") {
7                       Task {
8                           data = await getData()
9                       }
10                  }.buttonStyle(.bordered)

11                  Text("Data: \(data)")
12              }
13          }
14      }

15      private func getData() async -> String {
16          return "World"
17      }

When user clicks on data in line 3, Xcode should show "non-isolated".

When user clicks on somewhere inside the Task closure (line 7-9), Xcode should show "main-actor".

When user clicks on getData() in line 8, however, Xcode should show something like ... I don't have a good name for it, maybe "non-isolated"?

If user clicks in a custom actor's code (the example doesn't have it), Xcode should show the actor's name. In Task.detached case, it would be something like "anonymous actor - <id>" (the id is to differentiate different anonymous actors).

Concurrency information available at compile time

I'm aware some information are available only at runtime. One example is which exact thread in the cooperative thread pool getData() will run in. The feature doesn't intend to provide details like that, because a) it can't, and b) in most case what user'd like to know is if a func runs in main actor, a custome actor, or in a non-isolated way. My understanding is those information are available at compile time.

Why error message isn't enough

I notice that error message contains helpful information to debug concurrency issue. But it has a few limitations:

First, it's a "trial and error" approach.

Second and more importantly, it doesn't help user understanding working code. There are situations where the code works but user misunderstands how it actually works. Take the above code as an example, I misundertood how it worked at first. Given the fact that a) I read from the doc that Task inherits the current actor context, and b) the compiler didn't complain about line 8, I thought that data was protected by main actor. But that's not true, and it's hard to figure it out without experiments.


I personally think this will be a useful feature and from my understanding it's feasible. What do you people think? Comments are welcome.

This needs to be sent to Apple as a feature request,

Send us your feedback and report bugs

Tells you how too.

I agree, to me this also feels to be Xcode-specific and should be filed in Feedback Assistant. Unless the OP can elaborate how this would work with SourceKit-LSP and editors that support it.

I'm not sure about the solution suggested by OP, but I understand the criticism. On the one hand we say its easy to know where an async function runs as we can see from its annotation, but on the other there's lots of situations where that annotation is implicit – and that's quite confusing for newcomers (and me.)

One enhancement that might make things clearer is if types that conform to protocols with members annotated with a GAIT (e.g. @MainActor var body: some View in SwiftUI) have the compiler enforce that the implementation is also annotated with the GAIT.

So we'd get something like:

struct MyView: View {
  // ERROR: `body` is missing `@MainActor` annotation
  var body: some View {
    Text("Which concurrency context do I run within?!")
  }
}

With the fix to prefix the body member with @MainActor.

Now, that does leave the complication of SwiftUI Views which magically, to me at least, change to be @MainActor isolated across all members when certain property wrappers are added, but hopefully it might be as simple as:

// ERROR: View types which use managed state must be annotated with `@MainActor`
struct MyView: View {
  @State private var message = "Which concurrency context do I run within?!"
  var body: some View {
    Text("\(message)")
  }
}

With the fix to prefix the type definition with @MainActor i.e. @MainActor struct MyView: View { ... }.

Perhaps this can be a Swift 6 thing.

I expected suggestion (or criticism) like this. That's why I carefully put "Compiler support for" in the title and explained it clearly in the second second sentence in the post.

Are you suggesting this is infeasible technically? I know little about SourceKit-LSP. I just wanted to bring up the idea because I thought it would be useful. That's why I called it pre-pitch.