Compiler thinks non-async property is async?

I am getting an error from the compiler:

Expression is 'async' but is not marked with 'await'

But the expression is not async.

Here's a minimalist example:

func testAsync() async -> String {
    let result = App.instance.dataManager.getData() // ERROR: Expression is 'async' but is not marked with 'await'
    ...
     async stuff here
    ...
    return result
}

The error occurs on the first line of this function. But getData() is not async, nor is dataManager an async property.

I can get rid of the error if I get rid of the singleton instance property:

func testAsync() async -> String {
    let dataManager = DataManager() // no error
    let result = dataManager.getData() // no error
    ...
      async stuff here
    ...
    return result
}

But neither the singleton nor the instance property are async. If I comment out the "async stuff" and remove async from the function declaration, it builds fine.

Is this a compiler error or am I missing something?

Is this a compiler error or am I missing something?

It’s hard to say without more context. If you pull the relevant declarations out into a small test project, does it fail in the same way? If so, please post the code.

ps Pasted in below is my attempt at this. It doesn’t show the error, so there’s clearly something contextual going on, and the trick is to plicate the context from your app into your test project.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

struct App {
    static let instance = App()
    
    var dataManager = DataManager()
}

struct DataManager {
    func getData() -> String {
        return ""
    }
}

func testAsync() async -> String {
    let result = App.instance.dataManager.getData()
    return result
}

Is your App type an actor, rather than struct or class? In @eskimo’s code above, changing struct App to actor App produces the error message you reported.

Is there a downside to that … ?

Not as such, but I’m reluctant to recommend that. There are two potential causes of this problem:

  • You misunderstanding your own code.

  • A bug in the compiler.

If it’s the latter, then this might be a reasonable workaround, but if it’s the former then, yeah, that’s not good.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I had a breakthrough after reading @Scott's comment. It sure was behaving as if the compiler thought it was an actor.

As a test, I removed the private restriction on the singleton's initializer and tried to initialize it. I got a very revealing error:

func testAsync() async -> String {
    let app = App() // ERROR: Calls to initializer 'init()' from outside of its actor context are implicitly asynchronous
    ...
     async stuff here
    ...
    return result
}

Well, it turns out that App is a UISplitViewControllerDelegate and that protocol is a @MainActor! If I remove the protocol from its definition the errors go away.

Is this correct behavior? I tried, but haven't been able to re-create the issue in a simple test case.

In any case, thanks @eskimo and @Scott for helping me clear this up!

Compiler thinks non-async property is async?
 
 
Q