Calling borrowing method of stored property existential leads to consume of self

Hi,

I’m continueing my experiments with noncopyable types and ownership in Swift and ran into what looks a bit surprising to me:

protocol BulkChanges: ~Escapable, Sendable {
    func append(_ integer: Int)
}

protocol ShardData: ~Copyable, Sendable {
    associatedtype T: BulkChanges

    borrowing func withBulkChanges<R>(
        _ body: (borrowing Self.T) throws -> R
    ) rethrows -> R
}

protocol API {
    func makeP2() -> any (ShardData & ~Copyable)
}

struct Shard: ~Copyable {
    let shardData: any (ShardData & ~Copyable)

    mutating func run() {
        self.shardData.withBulkChanges { bulkChanges in
            bulkChanges.append(42)
        }
        // ❌ error: Missing reinitialization of inout parameter 'self' after consume
    }
}

That seems that I specified correctly that withBulkChanges is borrowing shardData and closure should not capture self.

Interestingly, the following workaround compiles:

extension Shard {
    borrowing func withShardData<R>(
        _ body: (borrowing any (ShardData & ~Copyable)) throws -> R
    ) rethrows -> R {
        try body(self.shardData)
    }

    mutating func run() {
        self.withShardData { shardData in
            shardData.withBulkChanges { bulkChanges in
                bulkChanges.append(43)
            }
        }
    }
}

I wonder if I do smth wrong or should I consider it as a compiler bug in one of the cases?

2 Likes