`Sendable` values in non-`Sendable` containers

Disclaimer: this code is simplified for demonstration purposes.

Suppose I have a value only available asynchronously:

struct Source: Sendable {
    var someAsyncValue: Int {
        get async {
            42
        }
    }
}

That value is a part of a dependency:

class Dependency {
    let source = Source()

    var someAsyncValue: Int {
        get async {
            await source.someAsyncValue
        }
    }
}

And this is then used in some code:

struct Container {

    let dependency = Dependency()

    @MainActor func worksFine() async { 
        _ = await self.dependency.source.someAsyncValue // ✅
    }
}

This is a repeated pattern, so I introduce a "shortcut" into Dependency, so I don't have to write .source every time:

extension Dependency {
    var someAsyncValue: Int {
        get async {
            await source.someAsyncValue
        }
    }
}

Predictably, this doesn't work, because dependency is neither Sendable, nor @MainActor.

struct Container {

    let dependency = Dependency()

    @MainActor func doesNotWork() async {
        _ = await self.dependency.someAsyncValue // ❌ Non-sendable type 'Dependency' exiting main actor-isolated context in call to nonisolated property 'someAsyncValue' cannot cross actor boundary
    }
}

This Dependency could easily be made Sendable, but the real one has mutable state, so that's out. It could be made into an actor or isolated to @MainActor, but the real version also conforms to protocols, which is another can of worms.

The method on Container is @MainActor because some other non-Sendable classes are later involved, calling more async methods. Removing @MainActor would just shift the problem elsewhere.

I could mark someAsyncValue with @MainActor, but it's a simple value... there is really no reason it should have to be isolated.

I only want to be able to avoid having to write .source, not rearchitect the whole app :sweat_smile:. My question is whether I've overlooked something (please) or whether I'll just have to bite the bullet here.