Dynamic casting should unwrap optional values
Current Behavior
Dynamic casting (failable casting as?, and force casting as!) an optional value (potentially type-erased to an existential) to a non-optional type currently fails (e.g. failable casting results in nil).
Expected Behavior
I expected (but perhaps shouldn't have) that an optional value being casted into a subtype it conforms to would unwrap it. I'm really not sure if this is a bug or if it's expected though
Steps To Reproduce
I've made a repro contract/transactions to demonstrate
https://github.com/austinkline/cadence-burner-bug
Environment
- Cadence version:Version: v1.15.0-cadence-v1.0.0-preview.12, Commit: c582e63baf4581e4cf021a9b1917c198ca5b6065
- Network: emulator
Discord thread: https://discord.com/channels/613813861610684416/621847426201944074/1219773414949126234
I guess that makes sense. For example, Swift also supports unwrapping using casting:
let hello: String??? = "hello"
let something: Any = hello
something as! String // "hello" of type `String`
However, casting to Any does not:
something as! Any // Optional(Optional(Optional("hello"))) of type `String???`
Then again, the behaviour does not seem to be about existential types, because those are also unwrapped:
protocol I {}
struct S: I {}
let hello: S???? = S()
let something: Any = hello
something as! any I // S() of type `S`, not `Optional(Optional(Optional(S())))` of type `S???`