- Notifications
You must be signed in to change notification settings - Fork10.6k
Open
Description
Description
If an Encodable is wrapped up as a value in a dictionary, and you encode the dictionary with PropertyListEncoder in a background actor, the app crashes with the curious claim: "Could not cast value of type Whatever to 'Swift.Encodable', even though the type Whatever is clearly marked as Encodable.
Reproduction
import FoundationstructThing:Codable{letname:String}actorActorWhoEncodes{vardict=[String: Thing]()func encode(thing:Thing)throws->Data?{dict["testing"]= thingreturntryPropertyListEncoder().encode(dict)}}
And then, elsewhere, something of this sort (run on themain actor):
Task{tryawaitActorWhoEncodes().encode(thing:Thing(name:"matt")) // Crash! Could not cast value of type 'PropertyListEncoderTest.Thing' // to 'Swift.Encodable'}
Expected behavior
Either we should not crash or we should not have compiled in the first place.
Environment
swift-driver version: 1.127.14.1 Apple Swift version 6.2.1 (swiftlang-6.2.1.4.8 clang-1700.4.4.1)Target: arm64-apple-macosx26.0Additional information
Ultimately I found a workaround! Namely, conformnonisolated to Codable:
struct Thing: nonisolated Codable {So, whether there is a bug here and what the bug is, I leave to you. I can think of three possible responses:
- No bug. This is all expected and is what you get for not saying
nonisolated Codablein the first place, if you were thinking of using PropertyListEncoder in an actor. - The bug is the failure of the compiler to call out the problem. It's interesting that if you tell the PropertyListEncoder to
encode(thing), you get a helpful compiler error: "Main actor-isolated conformance of 'Thing' to 'Encodable' cannot be used in actor-isolated context". Thus, one might argue that the real trouble here is that when what we encode is a Thing wrapped in a Dictionary, there is no compile-time error. However, it may be that the compiler just doesn't have the cojones to think as deep as it would need to in order to notice the issue. - It's a bug (and perhaps is just a sign of issues with using PropertyListEncoder under Swift concurrency; it wouldn't be the first time someone has pointedthat out).